🔍 TwinCAT 코드 QA 분석 보고서

생성 일시: 2025-11-28 15:36:38

분석 시간: 1.29초

이전 버전: temp_empty_compare

신규 버전: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1

📊 이슈 요약

🔴 Critical

2829

🟡 Warning

1201

🔵 Info

123

📈 변경 사항 통계

항목개수
변수 변경3028
로직 변경124
데이터 타입 변경169

🚨 이슈 상세

🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:10

설명: Range_1_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Range_1_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Range_1_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Range_1_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Range_1_Value : REAL; // 초기값 없음!

✅ 안전: Range_1_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:11

설명: Range_2_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Range_2_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Range_2_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Range_2_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Range_2_Value : REAL; // 초기값 없음!

✅ 안전: Range_2_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:13

설명: Para_1_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Para_1_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Para_1_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Para_1_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Para_1_Value : REAL; // 초기값 없음!

✅ 안전: Para_1_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:14

설명: Para_2_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Para_2_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Para_2_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Para_2_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Para_2_Value : REAL; // 초기값 없음!

✅ 안전: Para_2_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:16

설명: RangeNo (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   RangeNo : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       RangeNo : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       RangeNo := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: RangeNo : UINT; // 초기값 없음!

✅ 안전: RangeNo : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:17

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:10

설명: Range_1_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Range_1_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Range_1_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Range_1_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Range_1_Value : REAL; // 초기값 없음!

✅ 안전: Range_1_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:11

설명: Range_2_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Range_2_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Range_2_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Range_2_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Range_2_Value : REAL; // 초기값 없음!

✅ 안전: Range_2_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:13

설명: Para_1_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Para_1_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Para_1_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Para_1_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Para_1_Value : REAL; // 초기값 없음!

✅ 안전: Para_1_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:14

설명: Para_2_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Para_2_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Para_2_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Para_2_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Para_2_Value : REAL; // 초기값 없음!

✅ 안전: Para_2_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:16

설명: RangeNo (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   RangeNo : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       RangeNo : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       RangeNo := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: RangeNo : UINT; // 초기값 없음!

✅ 안전: RangeNo : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:17

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Add_EventLog_buffer.TcPOU:12

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_CheckMainZone.TcPOU:2

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_CheckMFCUse.TcPOU:2

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:3

설명: Start (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Start : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Start : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Start := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Start : UINT; // 초기값 없음!

✅ 안전: Start : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:4

설명: End (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   End : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       End : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       End := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: End : UINT; // 초기값 없음!

✅ 안전: End : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:13

설명: Duplication_Step_Count (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Duplication_Step_Count : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Duplication_Step_Count : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Duplication_Step_Count := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Duplication_Step_Count : UINT; // 초기값 없음!

✅ 안전: Duplication_Step_Count : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:18

설명: NextStep (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   NextStep : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       NextStep : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       NextStep := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: NextStep : UINT; // 초기값 없음!

✅ 안전: NextStep : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:22

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:23

설명: loop (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   loop : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       loop : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       loop := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: loop : UINT; // 초기값 없음!

✅ 안전: loop : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:3

설명: Start (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Start : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Start : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Start := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Start : UINT; // 초기값 없음!

✅ 안전: Start : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:4

설명: End (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   End : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       End : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       End := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: End : UINT; // 초기값 없음!

✅ 안전: End : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:13

설명: Duplication_Step_Count (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Duplication_Step_Count : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Duplication_Step_Count : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Duplication_Step_Count := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Duplication_Step_Count : UINT; // 초기값 없음!

✅ 안전: Duplication_Step_Count : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:18

설명: NextStep (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   NextStep : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       NextStep : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       NextStep := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: NextStep : UINT; // 초기값 없음!

✅ 안전: NextStep : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:22

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:23

설명: loop (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   loop : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       loop : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       loop := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: loop : UINT; // 초기값 없음!

✅ 안전: loop : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_APC.TcPOU:6

설명: dCheckSum (DWORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   dCheckSum : DWORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       dCheckSum : DWORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       dCheckSum := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: dCheckSum : DWORD; // 초기값 없음!

✅ 안전: dCheckSum : DWORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_APC.TcPOU:9

설명: Loop (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Loop : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Loop : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Loop := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Loop : INT; // 초기값 없음!

✅ 안전: Loop : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_APC_PID.TcPOU:3

설명: iPID_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iPID_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iPID_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iPID_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iPID_Value : REAL; // 초기값 없음!

✅ 안전: iPID_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_APC_PID.TcPOU:4

설명: iPrecision (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iPrecision : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iPrecision : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iPrecision := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iPrecision : INT; // 초기값 없음!

✅ 안전: iPrecision : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Boat_Elevator.TcPOU:8

설명: dCheckSum (DWORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   dCheckSum : DWORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       dCheckSum : DWORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       dCheckSum := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: dCheckSum : DWORD; // 초기값 없음!

✅ 안전: dCheckSum : DWORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Boat_Elevator.TcPOU:13

설명: Loop (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Loop : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Loop : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Loop := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Loop : INT; // 초기값 없음!

✅ 안전: Loop : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Extract_Array.TcPOU:3

설명: iSize (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iSize : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iSize : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iSize := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iSize : UINT; // 초기값 없음!

✅ 안전: iSize : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Extract_Array.TcPOU:12

설명: Loop (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Loop : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Loop : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Loop := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Loop : UINT; // 초기값 없음!

✅ 안전: Loop : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Read_Array.TcPOU:3

설명: iSize (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iSize : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iSize : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iSize := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iSize : UINT; // 초기값 없음!

✅ 안전: iSize : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Read_Array.TcPOU:7

설명: Index (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Index : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Index : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Index := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Index : UINT; // 초기값 없음!

✅ 안전: Index : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Write_Array.TcPOU:4

설명: iSize (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iSize : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iSize : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iSize := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iSize : UINT; // 초기값 없음!

✅ 안전: iSize : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Write_Array.TcPOU:8

설명: Index (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Index : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Index : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Index := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Index : UINT; // 초기값 없음!

✅ 안전: Index : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Write_Array.TcPOU:11

설명: rData (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rData : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rData : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rData := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rData : REAL; // 초기값 없음!

✅ 안전: rData : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Write_Array.TcPOU:12

설명: wData (DWORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   wData : DWORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       wData : DWORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       wData := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: wData : DWORD; // 초기값 없음!

✅ 안전: wData : DWORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_EventLog_Shift.TcPOU:10

설명: f2 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   f2 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       f2 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       f2 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: f2 : REAL; // 초기값 없음!

✅ 안전: f2 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_EventLog_Shift.TcPOU:12

설명: i (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : INT; // 초기값 없음!

✅ 안전: i : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_FFU_CheckSum_Send.TcPOU:3

설명: iSize (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iSize : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iSize : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iSize := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iSize : UINT; // 초기값 없음!

✅ 안전: iSize : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_FFU_CheckSum_Send.TcPOU:8

설명: x_byte (BYTE): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   x_byte : BYTE := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       x_byte : BYTE := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       x_byte := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: x_byte : BYTE; // 초기값 없음!

✅ 안전: x_byte : BYTE := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_FFU_CheckSum_Send.TcPOU:9

설명: Loop (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Loop : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Loop : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Loop := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Loop : UINT; // 초기값 없음!

✅ 안전: Loop : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Function_LV_Log.TcPOU:2

설명: iValue (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iValue : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iValue : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iValue := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iValue : REAL; // 초기값 없음!

✅ 안전: iValue : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Function_Process_Log.TcPOU:2

설명: iValue (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iValue : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iValue : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iValue := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iValue : REAL; // 초기값 없음!

✅ 안전: iValue : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Function_Process_Log.TcPOU:3

설명: iDec (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iDec : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iDec : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iDec := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iDec : INT; // 초기값 없음!

✅ 안전: iDec : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Get_Parameter.TcPOU:5

설명: srcSize (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   srcSize : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       srcSize : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       srcSize := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: srcSize : UDINT; // 초기값 없음!

✅ 안전: srcSize : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Get_Parameter.TcPOU:9

설명: i (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UDINT; // 초기값 없음!

✅ 안전: i : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Get_Parameter.TcPOU:10

설명: size (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   size : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       size : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       size := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: size : UDINT; // 초기값 없음!

✅ 안전: size : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Process.TcPOU:5

설명: uiCntStep (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   uiCntStep : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       uiCntStep : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       uiCntStep := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: uiCntStep : UINT; // 초기값 없음!

✅ 안전: uiCntStep : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Parameter_Check.TcPOU:3

설명: srcAddr (POINTER): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   srcAddr : POINTER := NULL;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       srcAddr : POINTER := NULL;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       srcAddr := NULL;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: srcAddr : POINTER; // 초기값 없음!

✅ 안전: srcAddr : POINTER := NULL;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Parameter_Check.TcPOU:4

설명: srcSize (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   srcSize : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       srcSize : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       srcSize := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: srcSize : UDINT; // 초기값 없음!

✅ 안전: srcSize : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Parameter_Check.TcPOU:8

설명: i (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UDINT; // 초기값 없음!

✅ 안전: i : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Parameter_Check.TcPOU:9

설명: size (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   size : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       size : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       size := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: size : UDINT; // 초기값 없음!

✅ 안전: size : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Parameter_Check.TcPOU:10

설명: currIndex (POINTER): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   currIndex : POINTER := NULL;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       currIndex : POINTER := NULL;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       currIndex := NULL;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: currIndex : POINTER; // 초기값 없음!

✅ 안전: currIndex : POINTER := NULL;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_RealRound.TcPOU:2

설명: lValue (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   lValue : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       lValue : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       lValue := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: lValue : LREAL; // 초기값 없음!

✅ 안전: lValue : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_RealRound.TcPOU:3

설명: nDigit (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nDigit : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nDigit : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nDigit := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nDigit : UINT; // 초기값 없음!

✅ 안전: nDigit : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Set_Parameter.TcPOU:2

설명: paramAddr (POINTER): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   paramAddr : POINTER := NULL;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       paramAddr : POINTER := NULL;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       paramAddr := NULL;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: paramAddr : POINTER; // 초기값 없음!

✅ 안전: paramAddr : POINTER := NULL;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Set_Parameter.TcPOU:3

설명: paramSize (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   paramSize : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       paramSize : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       paramSize := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: paramSize : UDINT; // 초기값 없음!

✅ 안전: paramSize : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Set_Parameter.TcPOU:8

설명: i (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UDINT; // 초기값 없음!

✅ 안전: i : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Set_Parameter.TcPOU:9

설명: size (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   size : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       size : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       size := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: size : UDINT; // 초기값 없음!

✅ 안전: size : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Set_Parameter.TcPOU:10

설명: currIndex (POINTER): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   currIndex : POINTER := NULL;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       currIndex : POINTER := NULL;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       currIndex := NULL;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: currIndex : POINTER; // 초기값 없음!

✅ 안전: currIndex : POINTER := NULL;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_StepName_Search.TcPOU:6

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Table_Check.TcPOU:2

설명: CheckNum (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   CheckNum : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       CheckNum : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       CheckNum := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: CheckNum : UINT; // 초기값 없음!

✅ 안전: CheckNum : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Table_Check.TcPOU:3

설명: MaxTable (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   MaxTable : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       MaxTable : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       MaxTable := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: MaxTable : UINT; // 초기값 없음!

✅ 안전: MaxTable : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\Get_IEEE754.TcPOU:6

설명: f2 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   f2 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       f2 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       f2 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: f2 : REAL; // 초기값 없음!

✅ 안전: f2 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\Get_IEEE754.TcPOU:8

설명: i (DWORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : DWORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : DWORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : DWORD; // 초기값 없음!

✅ 안전: i : DWORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\Put_IEEE754.TcPOU:2

설명: rData (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rData : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rData : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rData := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rData : REAL; // 초기값 없음!

✅ 안전: rData : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\Put_IEEE754.TcPOU:5

설명: w (DWORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   w : DWORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       w : DWORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       w := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: w : DWORD; // 초기값 없음!

✅ 안전: w : DWORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_ROUND.TcPOU:2

설명: lValue (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   lValue : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       lValue : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       lValue := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: lValue : REAL; // 초기값 없음!

✅ 안전: lValue : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_ROUND.TcPOU:3

설명: nDigit (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nDigit : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nDigit : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nDigit := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nDigit : UINT; // 초기값 없음!

✅ 안전: nDigit : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_ROUND.TcPOU:4

설명: bRound (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bRound : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bRound : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bRound := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bRound : BOOL; // 초기값 없음!

✅ 안전: bRound : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_TO_STR.TcPOU:2

설명: in_fValue (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   in_fValue : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       in_fValue : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       in_fValue := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: in_fValue : REAL; // 초기값 없음!

✅ 안전: in_fValue : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_TO_STR.TcPOU:3

설명: in_nDigit (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   in_nDigit : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       in_nDigit : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       in_nDigit := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: in_nDigit : INT; // 초기값 없음!

✅ 안전: in_nDigit : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_TO_STR.TcPOU:6

설명: fConvertValue (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fConvertValue : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fConvertValue : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fConvertValue := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fConvertValue : REAL; // 초기값 없음!

✅ 안전: fConvertValue : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_TO_STR.TcPOU:7

설명: i (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : INT; // 초기값 없음!

✅ 안전: i : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:2

설명: iIndex (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iIndex : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iIndex : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iIndex := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iIndex : UINT; // 초기값 없음!

✅ 안전: iIndex : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:4

설명: iPost (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iPost : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iPost : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iPost := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iPost : BOOL; // 초기값 없음!

✅ 안전: iPost : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:5

설명: iClear (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iClear : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iClear : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iClear := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iClear : BOOL; // 초기값 없음!

✅ 안전: iClear : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:13

설명: paramResult (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   paramResult : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       paramResult : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       paramResult := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: paramResult : BOOL; // 초기값 없음!

✅ 안전: paramResult : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:3

설명: fSetpointValue (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fSetpointValue : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fSetpointValue : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fSetpointValue := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fSetpointValue : LREAL; // 초기값 없음!

✅ 안전: fSetpointValue : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:4

설명: fActualValue (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fActualValue : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fActualValue : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fActualValue := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fActualValue : LREAL; // 초기값 없음!

✅ 안전: fActualValue : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:6

설명: bReset (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bReset : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bReset : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bReset := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bReset : BOOL; // 초기값 없음!

✅ 안전: bReset : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:8

설명: fCtrlCycleTime (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fCtrlCycleTime : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fCtrlCycleTime : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fCtrlCycleTime := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fCtrlCycleTime : LREAL; // 초기값 없음!

✅ 안전: fCtrlCycleTime : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:14

설명: fKp (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fKp : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fKp : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fKp := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fKp : LREAL; // 초기값 없음!

✅ 안전: fKp : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:15

설명: fTn (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fTn : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fTn : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fTn := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fTn : LREAL; // 초기값 없음!

✅ 안전: fTn : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:16

설명: fTv (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fTv : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fTv : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fTv := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fTv : LREAL; // 초기값 없음!

✅ 안전: fTv : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:17

설명: fTd (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fTd : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fTd : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fTd := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fTd : LREAL; // 초기값 없음!

✅ 안전: fTd : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:22

설명: fCtrlOutput (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fCtrlOutput : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fCtrlOutput : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fCtrlOutput := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fCtrlOutput : LREAL; // 초기값 없음!

✅ 안전: fCtrlOutput : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:23

설명: nErrorStatus (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nErrorStatus : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nErrorStatus : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nErrorStatus := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nErrorStatus : UINT; // 초기값 없음!

✅ 안전: nErrorStatus : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:14

설명: iScale (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iScale : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iScale : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iScale := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iScale : REAL; // 초기값 없음!

✅ 안전: iScale : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:15

설명: iRamp_Write (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRamp_Write : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRamp_Write : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRamp_Write := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRamp_Write : REAL; // 초기값 없음!

✅ 안전: iRamp_Write : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:16

설명: iRamp_Read (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRamp_Read : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRamp_Read : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRamp_Read := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRamp_Read : REAL; // 초기값 없음!

✅ 안전: iRamp_Read : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:17

설명: iCheck_LowBand (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iCheck_LowBand : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iCheck_LowBand : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iCheck_LowBand := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iCheck_LowBand : REAL; // 초기값 없음!

✅ 안전: iCheck_LowBand : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:18

설명: iWarning_LowBand (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iWarning_LowBand : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iWarning_LowBand : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iWarning_LowBand := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iWarning_LowBand : REAL; // 초기값 없음!

✅ 안전: iWarning_LowBand : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:19

설명: iAlarm_LowBand (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iAlarm_LowBand : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iAlarm_LowBand : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iAlarm_LowBand := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iAlarm_LowBand : REAL; // 초기값 없음!

✅ 안전: iAlarm_LowBand : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:20

설명: iCheck_HighBand (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iCheck_HighBand : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iCheck_HighBand : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iCheck_HighBand := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iCheck_HighBand : REAL; // 초기값 없음!

✅ 안전: iCheck_HighBand : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:21

설명: iWarning_HighBand (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iWarning_HighBand : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iWarning_HighBand : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iWarning_HighBand := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iWarning_HighBand : REAL; // 초기값 없음!

✅ 안전: iWarning_HighBand : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:22

설명: iAlarm_HighBand (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iAlarm_HighBand : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iAlarm_HighBand : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iAlarm_HighBand := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iAlarm_HighBand : REAL; // 초기값 없음!

✅ 안전: iAlarm_HighBand : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:23

설명: iDeadBand (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iDeadBand : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iDeadBand : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iDeadBand := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iDeadBand : REAL; // 초기값 없음!

✅ 안전: iDeadBand : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:28

설명: Parts_Use (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Parts_Use : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Parts_Use : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Parts_Use := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Parts_Use : INT; // 초기값 없음!

✅ 안전: Parts_Use : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:35

설명: iControlMode (BYTE): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iControlMode : BYTE := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iControlMode : BYTE := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iControlMode := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iControlMode : BYTE; // 초기값 없음!

✅ 안전: iControlMode : BYTE := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:41

설명: iSet (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iSet : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iSet : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iSet := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iSet : REAL; // 초기값 없음!

✅ 안전: iSet : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:42

설명: iFlow_IO (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iFlow_IO : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iFlow_IO : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iFlow_IO := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iFlow_IO : REAL; // 초기값 없음!

✅ 안전: iFlow_IO : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:47

설명: oFlow (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oFlow : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oFlow : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oFlow := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oFlow : REAL; // 초기값 없음!

✅ 안전: oFlow : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:48

설명: oSet_IO (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oSet_IO : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oSet_IO : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oSet_IO := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oSet_IO : REAL; // 초기값 없음!

✅ 안전: oSet_IO : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:49

설명: oFlowCheck (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oFlowCheck : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oFlowCheck : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oFlowCheck := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oFlowCheck : BOOL; // 초기값 없음!

✅ 안전: oFlowCheck : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:50

설명: oLeak (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oLeak : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oLeak : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oLeak := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oLeak : BOOL; // 초기값 없음!

✅ 안전: oLeak : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:51

설명: oNumIndex (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oNumIndex : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oNumIndex : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oNumIndex := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oNumIndex : UINT; // 초기값 없음!

✅ 안전: oNumIndex : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Pump.TcPOU:6

설명: iSet_IO (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iSet_IO : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iSet_IO : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iSet_IO := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iSet_IO : BOOL; // 초기값 없음!

✅ 안전: iSet_IO : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Pump.TcPOU:10

설명: oSet_IO (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oSet_IO : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oSet_IO : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oSet_IO := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oSet_IO : BOOL; // 초기값 없음!

✅ 안전: oSet_IO : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:6

설명: in_ui_Port_No (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   in_ui_Port_No : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       in_ui_Port_No : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       in_ui_Port_No := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: in_ui_Port_No : UINT; // 초기값 없음!

✅ 안전: in_ui_Port_No : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:7

설명: in_ui_FlowUnit (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   in_ui_FlowUnit : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       in_ui_FlowUnit : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       in_ui_FlowUnit := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: in_ui_FlowUnit : UINT; // 초기값 없음!

✅ 안전: in_ui_FlowUnit : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:8

설명: in_ui_MFC_Maker (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   in_ui_MFC_Maker : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       in_ui_MFC_Maker : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       in_ui_MFC_Maker := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: in_ui_MFC_Maker : UINT; // 초기값 없음!

✅ 안전: in_ui_MFC_Maker : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:9

설명: in_ui_Ramp_Set (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   in_ui_Ramp_Set : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       in_ui_Ramp_Set : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       in_ui_Ramp_Set := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: in_ui_Ramp_Set : UDINT; // 초기값 없음!

✅ 안전: in_ui_Ramp_Set : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:10

설명: in_b_WriteMSG (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   in_b_WriteMSG : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       in_b_WriteMSG : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       in_b_WriteMSG := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: in_b_WriteMSG : BOOL; // 초기값 없음!

✅ 안전: in_b_WriteMSG : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:11

설명: in_ui_Ramp_Read (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   in_ui_Ramp_Read : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       in_ui_Ramp_Read : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       in_ui_Ramp_Read := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: in_ui_Ramp_Read : UDINT; // 초기값 없음!

✅ 안전: in_ui_Ramp_Read : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:15

설명: out_ui_Full_Scale (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   out_ui_Full_Scale : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       out_ui_Full_Scale : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       out_ui_Full_Scale := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: out_ui_Full_Scale : UINT; // 초기값 없음!

✅ 안전: out_ui_Full_Scale : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:16

설명: out_ui_Flow_Unit (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   out_ui_Flow_Unit : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       out_ui_Flow_Unit : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       out_ui_Flow_Unit := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: out_ui_Flow_Unit : UINT; // 초기값 없음!

✅ 안전: out_ui_Flow_Unit : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:17

설명: out_byte_FlowUnit (BYTE): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   out_byte_FlowUnit : BYTE := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       out_byte_FlowUnit : BYTE := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       out_byte_FlowUnit := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: out_byte_FlowUnit : BYTE; // 초기값 없음!

✅ 안전: out_byte_FlowUnit : BYTE := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:18

설명: out_ui_Ramp_Time (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   out_ui_Ramp_Time : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       out_ui_Ramp_Time : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       out_ui_Ramp_Time := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: out_ui_Ramp_Time : UINT; // 초기값 없음!

✅ 안전: out_ui_Ramp_Time : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:19

설명: out_ui_Read_Set (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   out_ui_Read_Set : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       out_ui_Read_Set : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       out_ui_Read_Set := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: out_ui_Read_Set : UINT; // 초기값 없음!

✅ 안전: out_ui_Read_Set : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:23

설명: bTriger (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bTriger : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bTriger : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bTriger := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bTriger : BOOL; // 초기값 없음!

✅ 안전: bTriger : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:24

설명: ui_Ramp_Old_Set (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   ui_Ramp_Old_Set : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       ui_Ramp_Old_Set : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       ui_Ramp_Old_Set := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: ui_Ramp_Old_Set : UDINT; // 초기값 없음!

✅ 안전: ui_Ramp_Old_Set : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:25

설명: ui_Temp_Data (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   ui_Temp_Data : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       ui_Temp_Data : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       ui_Temp_Data := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: ui_Temp_Data : UINT; // 초기값 없음!

✅ 안전: ui_Temp_Data : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:31

설명: udi_ReadData (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   udi_ReadData : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       udi_ReadData : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       udi_ReadData := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: udi_ReadData : UDINT; // 초기값 없음!

✅ 안전: udi_ReadData : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:32

설명: udi_ReadSetData (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   udi_ReadSetData : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       udi_ReadSetData : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       udi_ReadSetData := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: udi_ReadSetData : UDINT; // 초기값 없음!

✅ 안전: udi_ReadSetData : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:33

설명: udi_WriteData (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   udi_WriteData : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       udi_WriteData : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       udi_WriteData := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: udi_WriteData : UDINT; // 초기값 없음!

✅ 안전: udi_WriteData : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:47

설명: ui_Write_Count (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   ui_Write_Count : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       ui_Write_Count : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       ui_Write_Count := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: ui_Write_Count : UDINT; // 초기값 없음!

✅ 안전: ui_Write_Count : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Explict_Message_Timer.TcPOU:2

설명: bEnable (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bEnable : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bEnable : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bEnable := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bEnable : BOOL; // 초기값 없음!

✅ 안전: bEnable : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Explict_Message_Timer.TcPOU:7

설명: bBlink (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bBlink : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bBlink : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bBlink := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bBlink : BOOL; // 초기값 없음!

✅ 안전: bBlink : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Heater_Group_Scan.TcPOU:2

설명: InValue (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   InValue : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       InValue : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       InValue := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: InValue : REAL; // 초기값 없음!

✅ 안전: InValue : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Heater_Group_Scan.TcPOU:15

설명: Old_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Old_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Old_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Old_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Old_Value : REAL; // 초기값 없음!

✅ 안전: Old_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:8

설명: bError (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bError : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bError : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bError := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bError : BOOL; // 초기값 없음!

✅ 안전: bError : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:9

설명: nLostFrames (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nLostFrames : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nLostFrames : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nLostFrames := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nLostFrames : UDINT; // 초기값 없음!

✅ 안전: nLostFrames : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:10

설명: fFramesPerSecond (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fFramesPerSecond : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fFramesPerSecond : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fFramesPerSecond := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fFramesPerSecond : LREAL; // 초기값 없음!

✅ 안전: fFramesPerSecond : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:11

설명: nLostQueuedFrames (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nLostQueuedFrames : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nLostQueuedFrames : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nLostQueuedFrames := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nLostQueuedFrames : UDINT; // 초기값 없음!

✅ 안전: nLostQueuedFrames : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:12

설명: fQueuedFramesPerSecond (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fQueuedFramesPerSecond : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fQueuedFramesPerSecond : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fQueuedFramesPerSecond := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fQueuedFramesPerSecond : LREAL; // 초기값 없음!

✅ 안전: fQueuedFramesPerSecond : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:18

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:25

설명: trgValue (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   trgValue : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       trgValue : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       trgValue := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: trgValue : BOOL; // 초기값 없음!

✅ 안전: trgValue : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal.TcPOU:6

설명: iValue (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iValue : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iValue : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iValue := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iValue : BOOL; // 초기값 없음!

✅ 안전: iValue : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal.TcPOU:13

설명: ioInterlock (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   ioInterlock : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       ioInterlock : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       ioInterlock := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: ioInterlock : BOOL; // 초기값 없음!

✅ 안전: ioInterlock : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_BurnBox.TcPOU:6

설명: iValue (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iValue : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iValue : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iValue := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iValue : BOOL; // 초기값 없음!

✅ 안전: iValue : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_Temp.TcPOU:6

설명: iValue (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iValue : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iValue : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iValue := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iValue : BOOL; // 초기값 없음!

✅ 안전: iValue : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_Temp.TcPOU:10

설명: iInterlock (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iInterlock : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iInterlock : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iInterlock := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iInterlock : BOOL; // 초기값 없음!

✅ 안전: iInterlock : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_Temp.TcPOU:14

설명: oInterlock (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oInterlock : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oInterlock : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oInterlock := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oInterlock : BOOL; // 초기값 없음!

✅ 안전: oInterlock : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_TempDelay.TcPOU:2

설명: InValue (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   InValue : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       InValue : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       InValue := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: InValue : BOOL; // 초기값 없음!

✅ 안전: InValue : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_TempDelay.TcPOU:3

설명: DelayTime (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DelayTime : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DelayTime : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DelayTime := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DelayTime : REAL; // 초기값 없음!

✅ 안전: DelayTime : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_TempDelay.TcPOU:7

설명: OutValue (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   OutValue : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       OutValue : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       OutValue := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: OutValue : BOOL; // 초기값 없음!

✅ 안전: OutValue : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_TempDelay.TcPOU:15

설명: TimerExecute (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   TimerExecute : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       TimerExecute : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       TimerExecute := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: TimerExecute : BOOL; // 초기값 없음!

✅ 안전: TimerExecute : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:4

설명: iValve (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iValve : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iValve : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iValve := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iValve : BOOL; // 초기값 없음!

✅ 안전: iValve : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:5

설명: iValve2 (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iValve2 : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iValve2 : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iValve2 := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iValve2 : BOOL; // 초기값 없음!

✅ 안전: iValve2 : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:6

설명: iCondition (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iCondition : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iCondition : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iCondition := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iCondition : BOOL; // 초기값 없음!

✅ 안전: iCondition : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:7

설명: iAlarm (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iAlarm : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iAlarm : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iAlarm := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iAlarm : UINT; // 초기값 없음!

✅ 안전: iAlarm : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:12

설명: oValve (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oValve : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oValve : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oValve := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oValve : BOOL; // 초기값 없음!

✅ 안전: oValve : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:13

설명: oValve2 (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oValve2 : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oValve2 : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oValve2 := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oValve2 : BOOL; // 초기값 없음!

✅ 안전: oValve2 : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:2

설명: iGInitCmd (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iGInitCmd : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iGInitCmd : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iGInitCmd := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iGInitCmd : BOOL; // 초기값 없음!

✅ 안전: iGInitCmd : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:3

설명: iGExecuteCmd (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iGExecuteCmd : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iGExecuteCmd : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iGExecuteCmd := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iGExecuteCmd : BOOL; // 초기값 없음!

✅ 안전: iGExecuteCmd : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:4

설명: iCalCmd (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iCalCmd : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iCalCmd : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iCalCmd := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iCalCmd : BOOL; // 초기값 없음!

✅ 안전: iCalCmd : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:5

설명: iScale (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iScale : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iScale : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iScale := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iScale : REAL; // 초기값 없음!

✅ 안전: iScale : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:12

설명: iPort_Addr (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iPort_Addr : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iPort_Addr : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iPort_Addr := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iPort_Addr : UINT; // 초기값 없음!

✅ 안전: iPort_Addr : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:14

설명: iFlowPV (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iFlowPV : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iFlowPV : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iFlowPV := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iFlowPV : REAL; // 초기값 없음!

✅ 안전: iFlowPV : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:15

설명: iUnit (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iUnit : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iUnit : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iUnit := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iUnit : UINT; // 초기값 없음!

✅ 안전: iUnit : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:31

설명: ioCalUnit (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   ioCalUnit : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       ioCalUnit : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       ioCalUnit := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: ioCalUnit : UINT; // 초기값 없음!

✅ 안전: ioCalUnit : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:32

설명: ioCalType (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   ioCalType : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       ioCalType : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       ioCalType := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: ioCalType : UINT; // 초기값 없음!

✅ 안전: ioCalType : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:33

설명: ioCalUpdate (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   ioCalUpdate : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       ioCalUpdate : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       ioCalUpdate := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: ioCalUpdate : UINT; // 초기값 없음!

✅ 안전: ioCalUpdate : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:34

설명: ioCalBefore (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   ioCalBefore : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       ioCalBefore : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       ioCalBefore := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: ioCalBefore : REAL; // 초기값 없음!

✅ 안전: ioCalBefore : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:35

설명: ioCalAfter (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   ioCalAfter : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       ioCalAfter : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       ioCalAfter := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: ioCalAfter : REAL; // 초기값 없음!

✅ 안전: ioCalAfter : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:36

설명: ioCalShift (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   ioCalShift : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       ioCalShift : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       ioCalShift := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: ioCalShift : REAL; // 초기값 없음!

✅ 안전: ioCalShift : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:37

설명: ioCalAccumShift (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   ioCalAccumShift : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       ioCalAccumShift : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       ioCalAccumShift := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: ioCalAccumShift : REAL; // 초기값 없음!

✅ 안전: ioCalAccumShift : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:38

설명: ioCalEndCondition (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   ioCalEndCondition : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       ioCalEndCondition : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       ioCalEndCondition := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: ioCalEndCondition : BOOL; // 초기값 없음!

✅ 안전: ioCalEndCondition : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:42

설명: oInitCtrl (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oInitCtrl : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oInitCtrl : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oInitCtrl := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oInitCtrl : BOOL; // 초기값 없음!

✅ 안전: oInitCtrl : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:43

설명: oExecuteCtrl (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oExecuteCtrl : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oExecuteCtrl : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oExecuteCtrl := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oExecuteCtrl : BOOL; // 초기값 없음!

✅ 안전: oExecuteCtrl : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:44

설명: oCalCtrl (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oCalCtrl : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oCalCtrl : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oCalCtrl := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oCalCtrl : BOOL; // 초기값 없음!

✅ 안전: oCalCtrl : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:45

설명: oSetFlow (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oSetFlow : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oSetFlow : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oSetFlow := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oSetFlow : REAL; // 초기값 없음!

✅ 안전: oSetFlow : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:46

설명: oError (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oError : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oError : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oError := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oError : BOOL; // 초기값 없음!

✅ 안전: oError : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:47

설명: oError_Num (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oError_Num : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oError_Num : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oError_Num := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oError_Num : UINT; // 초기값 없음!

✅ 안전: oError_Num : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:50

설명: oErrorPara (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oErrorPara : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oErrorPara : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oErrorPara := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oErrorPara : REAL; // 초기값 없음!

✅ 안전: oErrorPara : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:82

설명: rPara_DATA (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rPara_DATA : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rPara_DATA : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rPara_DATA := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rPara_DATA : REAL; // 초기값 없음!

✅ 안전: rPara_DATA : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:83

설명: rMonPara_DATA (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rMonPara_DATA : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rMonPara_DATA : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rMonPara_DATA := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rMonPara_DATA : REAL; // 초기값 없음!

✅ 안전: rMonPara_DATA : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas_PartsPara.TcPOU:6

설명: iPort_Addr (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iPort_Addr : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iPort_Addr : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iPort_Addr := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iPort_Addr : UINT; // 초기값 없음!

✅ 안전: iPort_Addr : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas_PartsPara.TcPOU:8

설명: iTimeout (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iTimeout : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iTimeout : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iTimeout := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iTimeout : INT; // 초기값 없음!

✅ 안전: iTimeout : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas_PartsPara.TcPOU:42

설명: rGasStandardNumber (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rGasStandardNumber : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rGasStandardNumber : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rGasStandardNumber := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rGasStandardNumber : UINT; // 초기값 없음!

✅ 안전: rGasStandardNumber : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas_PartsPara.TcPOU:45

설명: rScale (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rScale : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rScale : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rScale := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rScale : REAL; // 초기값 없음!

✅ 안전: rScale : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas_PartsPara.TcPOU:46

설명: rFlow_Offset (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rFlow_Offset : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rFlow_Offset : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rFlow_Offset := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rFlow_Offset : REAL; // 초기값 없음!

✅ 안전: rFlow_Offset : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas_PartsPara.TcPOU:47

설명: rPressureOffset (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rPressureOffset : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rPressureOffset : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rPressureOffset := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rPressureOffset : REAL; // 초기값 없음!

✅ 안전: rPressureOffset : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas_PartsPara.TcPOU:48

설명: rPressureOffset1 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rPressureOffset1 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rPressureOffset1 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rPressureOffset1 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rPressureOffset1 : REAL; // 초기값 없음!

✅ 안전: rPressureOffset1 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas_PartsPara.TcPOU:49

설명: rPressureOffset2 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rPressureOffset2 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rPressureOffset2 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rPressureOffset2 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rPressureOffset2 : REAL; // 초기값 없음!

✅ 안전: rPressureOffset2 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas_PartsPara.TcPOU:50

설명: rTimeSincePowerOn (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rTimeSincePowerOn : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rTimeSincePowerOn : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rTimeSincePowerOn := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rTimeSincePowerOn : UDINT; // 초기값 없음!

✅ 안전: rTimeSincePowerOn : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas_PartsPara.TcPOU:51

설명: rTotalTimePowered (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rTotalTimePowered : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rTotalTimePowered : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rTotalTimePowered := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rTotalTimePowered : UDINT; // 초기값 없음!

✅ 안전: rTotalTimePowered : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas_PartsPara.TcPOU:55

설명: rCfgExeStartFlow (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rCfgExeStartFlow : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rCfgExeStartFlow : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rCfgExeStartFlow := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rCfgExeStartFlow : REAL; // 초기값 없음!

✅ 안전: rCfgExeStartFlow : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas_PartsPara.TcPOU:56

설명: rCfgExeEndFlow (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rCfgExeEndFlow : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rCfgExeEndFlow : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rCfgExeEndFlow := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rCfgExeEndFlow : REAL; // 초기값 없음!

✅ 안전: rCfgExeEndFlow : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas_PartsPara.TcPOU:57

설명: rExeAlarmLimit (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rExeAlarmLimit : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rExeAlarmLimit : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rExeAlarmLimit := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rExeAlarmLimit : REAL; // 초기값 없음!

✅ 안전: rExeAlarmLimit : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Signal_2BYTE.TcPOU:2

설명: ALARM_Data (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   ALARM_Data : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       ALARM_Data : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       ALARM_Data := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: ALARM_Data : UINT; // 초기값 없음!

✅ 안전: ALARM_Data : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Signal_2BYTE.TcPOU:3

설명: iStartAlarm_Number (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iStartAlarm_Number : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iStartAlarm_Number : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iStartAlarm_Number := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iStartAlarm_Number : INT; // 초기값 없음!

✅ 안전: iStartAlarm_Number : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Signal_2BYTE.TcPOU:9

설명: i (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : INT; // 초기값 없음!

✅ 안전: i : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Signal_2BYTE.TcPOU:10

설명: iValue (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iValue : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iValue : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iValue := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iValue : BOOL; // 초기값 없음!

✅ 안전: iValue : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Signal_2BYTE.TcPOU:11

설명: Buffer_Data (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Buffer_Data : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Buffer_Data : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Buffer_Data := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Buffer_Data : UINT; // 초기값 없음!

✅ 안전: Buffer_Data : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:8

설명: WS_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   WS_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       WS_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       WS_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: WS_Value : REAL; // 초기값 없음!

✅ 안전: WS_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:9

설명: Spike_PV_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Spike_PV_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Spike_PV_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Spike_PV_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Spike_PV_Value : REAL; // 초기값 없음!

✅ 안전: Spike_PV_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:10

설명: Profile_PV_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Profile_PV_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Profile_PV_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Profile_PV_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Profile_PV_Value : REAL; // 초기값 없음!

✅ 안전: Profile_PV_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:12

설명: Temp_DEV_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Temp_DEV_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Temp_DEV_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Temp_DEV_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Temp_DEV_Value : REAL; // 초기값 없음!

✅ 안전: Temp_DEV_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:14

설명: Short_DEV_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Short_DEV_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Short_DEV_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Short_DEV_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Short_DEV_Value : REAL; // 초기값 없음!

✅ 안전: Short_DEV_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:15

설명: Short_WS_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Short_WS_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Short_WS_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Short_WS_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Short_WS_Value : REAL; // 초기값 없음!

✅ 안전: Short_WS_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:7

설명: Spike_PV_Value_1 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Spike_PV_Value_1 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Spike_PV_Value_1 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Spike_PV_Value_1 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Spike_PV_Value_1 : REAL; // 초기값 없음!

✅ 안전: Spike_PV_Value_1 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:8

설명: Spike_PV_Value_2 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Spike_PV_Value_2 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Spike_PV_Value_2 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Spike_PV_Value_2 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Spike_PV_Value_2 : REAL; // 초기값 없음!

✅ 안전: Spike_PV_Value_2 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:10

설명: Profile_PV_Value_1 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Profile_PV_Value_1 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Profile_PV_Value_1 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Profile_PV_Value_1 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Profile_PV_Value_1 : REAL; // 초기값 없음!

✅ 안전: Profile_PV_Value_1 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:11

설명: Profile_PV_Value_2 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Profile_PV_Value_2 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Profile_PV_Value_2 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Profile_PV_Value_2 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Profile_PV_Value_2 : REAL; // 초기값 없음!

✅ 안전: Profile_PV_Value_2 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:13

설명: Temp_DEV_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Temp_DEV_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Temp_DEV_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Temp_DEV_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Temp_DEV_Value : REAL; // 초기값 없음!

✅ 안전: Temp_DEV_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:6

설명: Spike_PV_Value_1 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Spike_PV_Value_1 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Spike_PV_Value_1 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Spike_PV_Value_1 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Spike_PV_Value_1 : REAL; // 초기값 없음!

✅ 안전: Spike_PV_Value_1 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:7

설명: Spike_PV_Value_2 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Spike_PV_Value_2 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Spike_PV_Value_2 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Spike_PV_Value_2 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Spike_PV_Value_2 : REAL; // 초기값 없음!

✅ 안전: Spike_PV_Value_2 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:9

설명: Profile_PV_Value_1 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Profile_PV_Value_1 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Profile_PV_Value_1 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Profile_PV_Value_1 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Profile_PV_Value_1 : REAL; // 초기값 없음!

✅ 안전: Profile_PV_Value_1 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:10

설명: Profile_PV_Value_2 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Profile_PV_Value_2 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Profile_PV_Value_2 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Profile_PV_Value_2 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Profile_PV_Value_2 : REAL; // 초기값 없음!

✅ 안전: Profile_PV_Value_2 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:12

설명: Temp_DEV_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Temp_DEV_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Temp_DEV_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Temp_DEV_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Temp_DEV_Value : REAL; // 초기값 없음!

✅ 안전: Temp_DEV_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:25

설명: _PV_Value_1 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   _PV_Value_1 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       _PV_Value_1 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       _PV_Value_1 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: _PV_Value_1 : REAL; // 초기값 없음!

✅ 안전: _PV_Value_1 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:26

설명: _PV_Value_2 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   _PV_Value_2 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       _PV_Value_2 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       _PV_Value_2 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: _PV_Value_2 : REAL; // 초기값 없음!

✅ 안전: _PV_Value_2 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Timer.TcPOU:2

설명: IN (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   IN : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       IN : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       IN := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: IN : BOOL; // 초기값 없음!

✅ 안전: IN : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Timer.TcPOU:6

설명: Q (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Q : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Q : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Q := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Q : BOOL; // 초기값 없음!

✅ 안전: Q : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Timer.TcPOU:9

설명: nTimeInc (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nTimeInc : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nTimeInc : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nTimeInc := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nTimeInc : UDINT; // 초기값 없음!

✅ 안전: nTimeInc : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:3

설명: iPort_Addr (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iPort_Addr : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iPort_Addr : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iPort_Addr := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iPort_Addr : UINT; // 초기값 없음!

✅ 안전: iPort_Addr : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:4

설명: iCalOffSetValue (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iCalOffSetValue : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iCalOffSetValue : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iCalOffSetValue := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iCalOffSetValue : REAL; // 초기값 없음!

✅ 안전: iCalOffSetValue : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:31

설명: rSerialNum (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rSerialNum : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rSerialNum : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rSerialNum := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rSerialNum : UDINT; // 초기값 없음!

✅ 안전: rSerialNum : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:7

설명: Condition (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Condition : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Condition : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Condition := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Condition : UINT; // 초기값 없음!

✅ 안전: Condition : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:8

설명: WS_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   WS_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       WS_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       WS_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: WS_Value : REAL; // 초기값 없음!

✅ 안전: WS_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:9

설명: PV_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   PV_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       PV_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       PV_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: PV_Value : REAL; // 초기값 없음!

✅ 안전: PV_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:10

설명: Low_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Low_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Low_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Low_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Low_Value : REAL; // 초기값 없음!

✅ 안전: Low_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:11

설명: High_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   High_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       High_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       High_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: High_Value : REAL; // 초기값 없음!

✅ 안전: High_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig.TcPOU:7

설명: WS_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   WS_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       WS_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       WS_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: WS_Value : REAL; // 초기값 없음!

✅ 안전: WS_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig.TcPOU:8

설명: PV_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   PV_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       PV_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       PV_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: PV_Value : REAL; // 초기값 없음!

✅ 안전: PV_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig.TcPOU:9

설명: Low_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Low_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Low_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Low_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Low_Value : REAL; // 초기값 없음!

✅ 안전: Low_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig.TcPOU:10

설명: High_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   High_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       High_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       High_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: High_Value : REAL; // 초기값 없음!

✅ 안전: High_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig.TcPOU:12

설명: iCheck (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iCheck : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iCheck : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iCheck := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iCheck : BOOL; // 초기값 없음!

✅ 안전: iCheck : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig_Sign.TcPOU:7

설명: WS_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   WS_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       WS_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       WS_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: WS_Value : REAL; // 초기값 없음!

✅ 안전: WS_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig_Sign.TcPOU:8

설명: PV_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   PV_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       PV_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       PV_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: PV_Value : REAL; // 초기값 없음!

✅ 안전: PV_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig_Sign.TcPOU:9

설명: Low_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Low_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Low_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Low_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Low_Value : REAL; // 초기값 없음!

✅ 안전: Low_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig_Sign.TcPOU:10

설명: High_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   High_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       High_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       High_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: High_Value : REAL; // 초기값 없음!

✅ 안전: High_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig_Sign.TcPOU:12

설명: iCheck (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iCheck : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iCheck : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iCheck := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iCheck : BOOL; // 초기값 없음!

✅ 안전: iCheck : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:55

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:56

설명: Temp_PT_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Temp_PT_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Temp_PT_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Temp_PT_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Temp_PT_Value : REAL; // 초기값 없음!

✅ 안전: Temp_PT_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:57

설명: iLoop (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iLoop : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iLoop : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iLoop := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iLoop : UINT; // 초기값 없음!

✅ 안전: iLoop : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:62

설명: Data_Change_Value (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Data_Change_Value : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Data_Change_Value : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Data_Change_Value := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Data_Change_Value : UINT; // 초기값 없음!

✅ 안전: Data_Change_Value : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:4

설명: iPressure1 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iPressure1 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iPressure1 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iPressure1 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iPressure1 : REAL; // 초기값 없음!

✅ 안전: iPressure1 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:5

설명: iPressure2 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iPressure2 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iPressure2 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iPressure2 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iPressure2 : REAL; // 초기값 없음!

✅ 안전: iPressure2 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:6

설명: iPID1 (BYTE): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iPID1 : BYTE := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iPID1 : BYTE := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iPID1 := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iPID1 : BYTE; // 초기값 없음!

✅ 안전: iPID1 : BYTE := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:7

설명: iPID2 (BYTE): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iPID2 : BYTE := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iPID2 : BYTE := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iPID2 := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iPID2 : BYTE; // 초기값 없음!

✅ 안전: iPID2 : BYTE := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:8

설명: iPosition (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iPosition : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iPosition : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iPosition := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iPosition : REAL; // 초기값 없음!

✅ 안전: iPosition : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:9

설명: iSlow_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iSlow_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iSlow_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iSlow_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iSlow_Pressure : REAL; // 초기값 없음!

✅ 안전: iSlow_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:10

설명: iSlow_Rate (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iSlow_Rate : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iSlow_Rate : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iSlow_Rate := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iSlow_Rate : REAL; // 초기값 없음!

✅ 안전: iSlow_Rate : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:11

설명: iSlowPID (BYTE): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iSlowPID : BYTE := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iSlowPID : BYTE := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iSlowPID := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iSlowPID : BYTE; // 초기값 없음!

✅ 안전: iSlowPID : BYTE := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:13

설명: iPID_Num (BYTE): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iPID_Num : BYTE := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iPID_Num : BYTE := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iPID_Num := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iPID_Num : BYTE; // 초기값 없음!

✅ 안전: iPID_Num : BYTE := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:24

설명: oError (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oError : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oError : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oError := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oError : BOOL; // 초기값 없음!

✅ 안전: oError : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:52

설명: Set_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Set_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Set_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Set_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Set_Value : REAL; // 초기값 없음!

✅ 안전: Set_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:53

설명: Read_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Read_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Read_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Read_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Read_Value : REAL; // 초기값 없음!

✅ 안전: Read_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:55

설명: iSet_Value (DINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iSet_Value : DINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iSet_Value : DINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iSet_Value := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iSet_Value : DINT; // 초기값 없음!

✅ 안전: iSet_Value : DINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:56

설명: iRead_Value (DINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRead_Value : DINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRead_Value : DINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRead_Value := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRead_Value : DINT; // 초기값 없음!

✅ 안전: iRead_Value : DINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:58

설명: Buff_nSubIndex (BYTE): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Buff_nSubIndex : BYTE := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Buff_nSubIndex : BYTE := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Buff_nSubIndex := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Buff_nSubIndex : BYTE; // 초기값 없음!

✅ 안전: Buff_nSubIndex : BYTE := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:59

설명: Buff_nIndex (WORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Buff_nIndex : WORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Buff_nIndex : WORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Buff_nIndex := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Buff_nIndex : WORD; // 초기값 없음!

✅ 안전: Buff_nIndex : WORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:60

설명: Buff_Set_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Buff_Set_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Buff_Set_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Buff_Set_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Buff_Set_Value : REAL; // 초기값 없음!

✅ 안전: Buff_Set_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:68

설명: Buff_iPressure1 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Buff_iPressure1 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Buff_iPressure1 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Buff_iPressure1 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Buff_iPressure1 : REAL; // 초기값 없음!

✅ 안전: Buff_iPressure1 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:69

설명: Buff_iPressure2 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Buff_iPressure2 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Buff_iPressure2 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Buff_iPressure2 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Buff_iPressure2 : REAL; // 초기값 없음!

✅ 안전: Buff_iPressure2 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:70

설명: Buff_iPosition (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Buff_iPosition : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Buff_iPosition : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Buff_iPosition := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Buff_iPosition : REAL; // 초기값 없음!

✅ 안전: Buff_iPosition : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:71

설명: Buff_iSlow_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Buff_iSlow_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Buff_iSlow_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Buff_iSlow_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Buff_iSlow_Pressure : REAL; // 초기값 없음!

✅ 안전: Buff_iSlow_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:72

설명: Buff_iSlow_Rate (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Buff_iSlow_Rate : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Buff_iSlow_Rate : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Buff_iSlow_Rate := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Buff_iSlow_Rate : REAL; // 초기값 없음!

✅ 안전: Buff_iSlow_Rate : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:80

설명: oldPressure1 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oldPressure1 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oldPressure1 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oldPressure1 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oldPressure1 : REAL; // 초기값 없음!

✅ 안전: oldPressure1 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:81

설명: oldPressure2 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oldPressure2 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oldPressure2 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oldPressure2 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oldPressure2 : REAL; // 초기값 없음!

✅ 안전: oldPressure2 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:82

설명: oldPosition (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oldPosition : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oldPosition : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oldPosition := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oldPosition : REAL; // 초기값 없음!

✅ 안전: oldPosition : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:83

설명: oldSlow_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oldSlow_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oldSlow_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oldSlow_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oldSlow_Pressure : REAL; // 초기값 없음!

✅ 안전: oldSlow_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:84

설명: oldSlow_Rate (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oldSlow_Rate : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oldSlow_Rate : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oldSlow_Rate := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oldSlow_Rate : REAL; // 초기값 없음!

✅ 안전: oldSlow_Rate : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:86

설명: old_iPID1 (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   old_iPID1 : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       old_iPID1 : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       old_iPID1 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: old_iPID1 : LREAL; // 초기값 없음!

✅ 안전: old_iPID1 : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:87

설명: old_iPID2 (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   old_iPID2 : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       old_iPID2 : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       old_iPID2 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: old_iPID2 : LREAL; // 초기값 없음!

✅ 안전: old_iPID2 : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:88

설명: old_iSlowPID (BYTE): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   old_iSlowPID : BYTE := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       old_iSlowPID : BYTE := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       old_iSlowPID := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: old_iSlowPID : BYTE; // 초기값 없음!

✅ 안전: old_iSlowPID : BYTE := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:2

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:3

설명: Step (BYTE): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Step : BYTE := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Step : BYTE := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Step := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Step : BYTE; // 초기값 없음!

✅ 안전: Step : BYTE := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:22

설명: Intensity_Real_Data (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Intensity_Real_Data : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Intensity_Real_Data : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Intensity_Real_Data := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Intensity_Real_Data : REAL; // 초기값 없음!

✅ 안전: Intensity_Real_Data : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:24

설명: i (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : INT; // 초기값 없음!

✅ 안전: i : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:25

설명: K (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   K : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       K : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       K := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: K : INT; // 초기값 없음!

✅ 안전: K : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:3

설명: Step (BYTE): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Step : BYTE := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Step : BYTE := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Step := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Step : BYTE; // 초기값 없음!

✅ 안전: Step : BYTE := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:23

설명: Intensity_Real_Data (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Intensity_Real_Data : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Intensity_Real_Data : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Intensity_Real_Data := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Intensity_Real_Data : REAL; // 초기값 없음!

✅ 안전: Intensity_Real_Data : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:24

설명: O2_Cal_Before_OriginData (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   O2_Cal_Before_OriginData : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       O2_Cal_Before_OriginData : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       O2_Cal_Before_OriginData := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: O2_Cal_Before_OriginData : REAL; // 초기값 없음!

✅ 안전: O2_Cal_Before_OriginData : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:25

설명: O2_Cal_After_OriginData (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   O2_Cal_After_OriginData : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       O2_Cal_After_OriginData : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       O2_Cal_After_OriginData := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: O2_Cal_After_OriginData : REAL; // 초기값 없음!

✅ 안전: O2_Cal_After_OriginData : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:28

설명: i (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : INT; // 초기값 없음!

✅ 안전: i : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:29

설명: K (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   K : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       K : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       K := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: K : INT; // 초기값 없음!

✅ 안전: K : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:15

설명: Loop (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Loop : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Loop : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Loop := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Loop : UINT; // 초기값 없음!

✅ 안전: Loop : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:16

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:17

설명: iValve (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iValve : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iValve : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iValve := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iValve : INT; // 초기값 없음!

✅ 안전: iValve : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:19

설명: iInitCtrl (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iInitCtrl : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iInitCtrl : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iInitCtrl := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iInitCtrl : BOOL; // 초기값 없음!

✅ 안전: iInitCtrl : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:20

설명: iExeCtrl (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iExeCtrl : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iExeCtrl : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iExeCtrl := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iExeCtrl : BOOL; // 초기값 없음!

✅ 안전: iExeCtrl : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:21

설명: iCalCtrl (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iCalCtrl : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iCalCtrl : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iCalCtrl := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iCalCtrl : BOOL; // 초기값 없음!

✅ 안전: iCalCtrl : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:27

설명: ErrorPara_Interface (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   ErrorPara_Interface : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       ErrorPara_Interface : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       ErrorPara_Interface := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: ErrorPara_Interface : REAL; // 초기값 없음!

✅ 안전: ErrorPara_Interface : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:28

설명: CalPara_Interface (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   CalPara_Interface : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       CalPara_Interface : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       CalPara_Interface := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: CalPara_Interface : REAL; // 초기값 없음!

✅ 안전: CalPara_Interface : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:29

설명: SetFlow (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SetFlow : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SetFlow : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SetFlow := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SetFlow : REAL; // 초기값 없음!

✅ 안전: SetFlow : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:31

설명: iMfcIndex (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iMfcIndex : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iMfcIndex : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iMfcIndex := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iMfcIndex : UINT; // 초기값 없음!

✅ 안전: iMfcIndex : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:11

설명: oBoatMode (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oBoatMode : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oBoatMode : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oBoatMode := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oBoatMode : INT; // 초기값 없음!

✅ 안전: oBoatMode : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:17

설명: oBoatTablePosition_1 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oBoatTablePosition_1 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oBoatTablePosition_1 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oBoatTablePosition_1 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oBoatTablePosition_1 : REAL; // 초기값 없음!

✅ 안전: oBoatTablePosition_1 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:18

설명: oBoatTablePosition_2 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oBoatTablePosition_2 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oBoatTablePosition_2 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oBoatTablePosition_2 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oBoatTablePosition_2 : REAL; // 초기값 없음!

✅ 안전: oBoatTablePosition_2 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:19

설명: oBoatTablePosition_3 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oBoatTablePosition_3 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oBoatTablePosition_3 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oBoatTablePosition_3 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oBoatTablePosition_3 : REAL; // 초기값 없음!

✅ 안전: oBoatTablePosition_3 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:20

설명: oBoatTablePosition_4 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oBoatTablePosition_4 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oBoatTablePosition_4 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oBoatTablePosition_4 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oBoatTablePosition_4 : REAL; // 초기값 없음!

✅ 안전: oBoatTablePosition_4 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:21

설명: oBoatTablePosition_5 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oBoatTablePosition_5 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oBoatTablePosition_5 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oBoatTablePosition_5 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oBoatTablePosition_5 : REAL; // 초기값 없음!

✅ 안전: oBoatTablePosition_5 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:23

설명: oBoatTableSpeed_1 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oBoatTableSpeed_1 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oBoatTableSpeed_1 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oBoatTableSpeed_1 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oBoatTableSpeed_1 : REAL; // 초기값 없음!

✅ 안전: oBoatTableSpeed_1 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:24

설명: oBoatTableSpeed_2 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oBoatTableSpeed_2 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oBoatTableSpeed_2 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oBoatTableSpeed_2 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oBoatTableSpeed_2 : REAL; // 초기값 없음!

✅ 안전: oBoatTableSpeed_2 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:25

설명: oBoatTableSpeed_3 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oBoatTableSpeed_3 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oBoatTableSpeed_3 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oBoatTableSpeed_3 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oBoatTableSpeed_3 : REAL; // 초기값 없음!

✅ 안전: oBoatTableSpeed_3 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:26

설명: oBoatTableSpeed_4 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oBoatTableSpeed_4 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oBoatTableSpeed_4 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oBoatTableSpeed_4 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oBoatTableSpeed_4 : REAL; // 초기값 없음!

✅ 안전: oBoatTableSpeed_4 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:27

설명: oBoatTableSpeed_5 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oBoatTableSpeed_5 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oBoatTableSpeed_5 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oBoatTableSpeed_5 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oBoatTableSpeed_5 : REAL; // 초기값 없음!

✅ 안전: oBoatTableSpeed_5 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:28

설명: oBoatUpSpeed (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oBoatUpSpeed : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oBoatUpSpeed : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oBoatUpSpeed := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oBoatUpSpeed : REAL; // 초기값 없음!

✅ 안전: oBoatUpSpeed : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:31

설명: oRotate_Speed (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oRotate_Speed : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oRotate_Speed : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oRotate_Speed := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oRotate_Speed : REAL; // 초기값 없음!

✅ 안전: oRotate_Speed : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:35

설명: Connected (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Connected : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Connected : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Connected := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Connected : BOOL; // 초기값 없음!

✅ 안전: Connected : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:37

설명: iBoatCurrentPosition (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoatCurrentPosition : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoatCurrentPosition : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoatCurrentPosition := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoatCurrentPosition : REAL; // 초기값 없음!

✅ 안전: iBoatCurrentPosition : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:38

설명: iBoatInitPosition (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoatInitPosition : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoatInitPosition : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoatInitPosition := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoatInitPosition : REAL; // 초기값 없음!

✅ 안전: iBoatInitPosition : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:39

설명: iBoatHomePosition (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoatHomePosition : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoatHomePosition : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoatHomePosition := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoatHomePosition : REAL; // 초기값 없음!

✅ 안전: iBoatHomePosition : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:40

설명: iBoatUpPosition (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoatUpPosition : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoatUpPosition : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoatUpPosition := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoatUpPosition : REAL; // 초기값 없음!

✅ 안전: iBoatUpPosition : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:41

설명: iBoatDownPosition (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoatDownPosition : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoatDownPosition : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoatDownPosition := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoatDownPosition : REAL; // 초기값 없음!

✅ 안전: iBoatDownPosition : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:42

설명: iBoatMaintPosition01 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoatMaintPosition01 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoatMaintPosition01 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoatMaintPosition01 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoatMaintPosition01 : REAL; // 초기값 없음!

✅ 안전: iBoatMaintPosition01 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:43

설명: iBoatMaintPosition02 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoatMaintPosition02 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoatMaintPosition02 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoatMaintPosition02 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoatMaintPosition02 : REAL; // 초기값 없음!

✅ 안전: iBoatMaintPosition02 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:44

설명: iBoatMaintPosition03 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoatMaintPosition03 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoatMaintPosition03 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoatMaintPosition03 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoatMaintPosition03 : REAL; // 초기값 없음!

✅ 안전: iBoatMaintPosition03 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:46

설명: iBoatCurrentSpeed (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoatCurrentSpeed : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoatCurrentSpeed : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoatCurrentSpeed := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoatCurrentSpeed : REAL; // 초기값 없음!

✅ 안전: iBoatCurrentSpeed : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:47

설명: iBoatAutoSpeed (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoatAutoSpeed : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoatAutoSpeed : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoatAutoSpeed := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoatAutoSpeed : REAL; // 초기값 없음!

✅ 안전: iBoatAutoSpeed : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:48

설명: iBoatJogSpeed (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoatJogSpeed : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoatJogSpeed : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoatJogSpeed := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoatJogSpeed : REAL; // 초기값 없음!

✅ 안전: iBoatJogSpeed : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:49

설명: iBoatInitSpeed (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoatInitSpeed : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoatInitSpeed : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoatInitSpeed := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoatInitSpeed : REAL; // 초기값 없음!

✅ 안전: iBoatInitSpeed : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:51

설명: iBoatACAC (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoatACAC : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoatACAC : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoatACAC := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoatACAC : REAL; // 초기값 없음!

✅ 안전: iBoatACAC : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:52

설명: iBoatACC (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoatACC : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoatACC : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoatACC := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoatACC : REAL; // 초기값 없음!

✅ 안전: iBoatACC : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:53

설명: iBoatDEC (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoatDEC : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoatDEC : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoatDEC := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoatDEC : REAL; // 초기값 없음!

✅ 안전: iBoatDEC : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:56

설명: iBoat_Servo (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoat_Servo : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoat_Servo : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoat_Servo := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoat_Servo : UDINT; // 초기값 없음!

✅ 안전: iBoat_Servo : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:57

설명: iBoat_Break (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoat_Break : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoat_Break : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoat_Break := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoat_Break : UDINT; // 초기값 없음!

✅ 안전: iBoat_Break : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:58

설명: iBoat_TP_Mode (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoat_TP_Mode : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoat_TP_Mode : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoat_TP_Mode := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoat_TP_Mode : UDINT; // 초기값 없음!

✅ 안전: iBoat_TP_Mode : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:59

설명: iBoat_HeaterShutter_Request_Mode (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoat_HeaterShutter_Request_Mode : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoat_HeaterShutter_Request_Mode : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoat_HeaterShutter_Request_Mode := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoat_HeaterShutter_Request_Mode : REAL; // 초기값 없음!

✅ 안전: iBoat_HeaterShutter_Request_Mode : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:62

설명: iBoatAlarmNum (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoatAlarmNum : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoatAlarmNum : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoatAlarmNum := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoatAlarmNum : UDINT; // 초기값 없음!

✅ 안전: iBoatAlarmNum : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:69

설명: iRotate_AlarmNum (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_AlarmNum : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_AlarmNum : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_AlarmNum := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_AlarmNum : UDINT; // 초기값 없음!

✅ 안전: iRotate_AlarmNum : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:71

설명: iRotate_Current_Position (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Current_Position : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Current_Position : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Current_Position := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Current_Position : REAL; // 초기값 없음!

✅ 안전: iRotate_Current_Position : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:72

설명: iRotate_Current_Degree (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Current_Degree : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Current_Degree : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Current_Degree := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Current_Degree : REAL; // 초기값 없음!

✅ 안전: iRotate_Current_Degree : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:74

설명: iRotate_Home_Position (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Home_Position : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Home_Position : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Home_Position := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Home_Position : REAL; // 초기값 없음!

✅ 안전: iRotate_Home_Position : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:75

설명: iRotate_Init_Position (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Init_Position : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Init_Position : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Init_Position := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Init_Position : REAL; // 초기값 없음!

✅ 안전: iRotate_Init_Position : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:76

설명: iRotate_Home_Speed (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Home_Speed : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Home_Speed : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Home_Speed := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Home_Speed : REAL; // 초기값 없음!

✅ 안전: iRotate_Home_Speed : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:77

설명: iRotate_Init_Speed (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Init_Speed : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Init_Speed : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Init_Speed := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Init_Speed : REAL; // 초기값 없음!

✅ 안전: iRotate_Init_Speed : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:78

설명: iRotate_Jog_Speed (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Jog_Speed : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Jog_Speed : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Jog_Speed := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Jog_Speed : REAL; // 초기값 없음!

✅ 안전: iRotate_Jog_Speed : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:79

설명: iRotate_Current_Speed (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Current_Speed : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Current_Speed : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Current_Speed := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Current_Speed : REAL; // 초기값 없음!

✅ 안전: iRotate_Current_Speed : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:81

설명: iRotate_ACAC (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_ACAC : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_ACAC : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_ACAC := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_ACAC : REAL; // 초기값 없음!

✅ 안전: iRotate_ACAC : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:82

설명: iRotate_AUTO_ACC (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_AUTO_ACC : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_AUTO_ACC : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_AUTO_ACC := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_AUTO_ACC : REAL; // 초기값 없음!

✅ 안전: iRotate_AUTO_ACC : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:83

설명: iRotate_AUTO_DEC (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_AUTO_DEC : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_AUTO_DEC : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_AUTO_DEC := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_AUTO_DEC : REAL; // 초기값 없음!

✅ 안전: iRotate_AUTO_DEC : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:84

설명: iRotate_TEMP (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_TEMP : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_TEMP : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_TEMP := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_TEMP : REAL; // 초기값 없음!

✅ 안전: iRotate_TEMP : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:86

설명: iRotate_Servo (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Servo : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Servo : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Servo := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Servo : UDINT; // 초기값 없음!

✅ 안전: iRotate_Servo : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:87

설명: iRotate_Break (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Break : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Break : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Break := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Break : UDINT; // 초기값 없음!

✅ 안전: iRotate_Break : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:88

설명: iRotate_TP_Mode (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_TP_Mode : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_TP_Mode : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_TP_Mode := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_TP_Mode : UDINT; // 초기값 없음!

✅ 안전: iRotate_TP_Mode : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:90

설명: iRotate_Sum_Load (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Sum_Load : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Sum_Load : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Sum_Load := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Sum_Load : REAL; // 초기값 없음!

✅ 안전: iRotate_Sum_Load : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:91

설명: iRotate_Cur_Load (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Cur_Load : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Cur_Load : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Cur_Load := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Cur_Load : REAL; // 초기값 없음!

✅ 안전: iRotate_Cur_Load : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:93

설명: iRotate_Driver_Set_Speed (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Driver_Set_Speed : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Driver_Set_Speed : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Driver_Set_Speed := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Driver_Set_Speed : REAL; // 초기값 없음!

✅ 안전: iRotate_Driver_Set_Speed : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:94

설명: iRotate_Driver_Current_Speed (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Driver_Current_Speed : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Driver_Current_Speed : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Driver_Current_Speed := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Driver_Current_Speed : REAL; // 초기값 없음!

✅ 안전: iRotate_Driver_Current_Speed : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:95

설명: iRotate_Current_Load (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Current_Load : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Current_Load : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Current_Load := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Current_Load : REAL; // 초기값 없음!

✅ 안전: iRotate_Current_Load : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:96

설명: iRotate_Torque (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Torque : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Torque : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Torque := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Torque : REAL; // 초기값 없음!

✅ 안전: iRotate_Torque : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:97

설명: iRotate_Driver_Alarm (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Driver_Alarm : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Driver_Alarm : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Driver_Alarm := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Driver_Alarm : UDINT; // 초기값 없음!

✅ 안전: iRotate_Driver_Alarm : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:98

설명: iRotate_1round_Load (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_1round_Load : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_1round_Load : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_1round_Load := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_1round_Load : REAL; // 초기값 없음!

✅ 안전: iRotate_1round_Load : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:99

설명: iRotate_Moment_Load (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iRotate_Moment_Load : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iRotate_Moment_Load : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iRotate_Moment_Load := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iRotate_Moment_Load : REAL; // 초기값 없음!

✅ 안전: iRotate_Moment_Load : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:112

설명: nRecBytes (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nRecBytes : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nRecBytes : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nRecBytes := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nRecBytes : UDINT; // 초기값 없음!

✅ 안전: nRecBytes : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:127

설명: SendSize (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SendSize : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SendSize : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SendSize := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SendSize : INT; // 초기값 없음!

✅ 안전: SendSize : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:148

설명: dwData (DWORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   dwData : DWORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       dwData : DWORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       dwData := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: dwData : DWORD; // 초기값 없음!

✅ 안전: dwData : DWORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:153

설명: oSpeed_Value (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oSpeed_Value : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oSpeed_Value : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oSpeed_Value := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oSpeed_Value : INT; // 초기값 없음!

✅ 안전: oSpeed_Value : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:4

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:4

설명: iPressure (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iPressure : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iPressure : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iPressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iPressure : LREAL; // 초기값 없음!

✅ 안전: iPressure : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:5

설명: iPosition (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iPosition : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iPosition : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iPosition := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iPosition : LREAL; // 초기값 없음!

✅ 안전: iPosition : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:10

설명: oError (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oError : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oError : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oError := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oError : BOOL; // 초기값 없음!

✅ 안전: oError : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:19

설명: oldPressure (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oldPressure : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oldPressure : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oldPressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oldPressure : LREAL; // 초기값 없음!

✅ 안전: oldPressure : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:20

설명: oldPosition (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   oldPosition : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       oldPosition : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       oldPosition := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: oldPosition : LREAL; // 초기값 없음!

✅ 안전: oldPosition : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:22

설명: Buff_iPressure (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Buff_iPressure : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Buff_iPressure : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Buff_iPressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Buff_iPressure : LREAL; // 초기값 없음!

✅ 안전: Buff_iPressure : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:23

설명: Buff_iPosition (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Buff_iPosition : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Buff_iPosition : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Buff_iPosition := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Buff_iPosition : LREAL; // 초기값 없음!

✅ 안전: Buff_iPosition : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:3

설명: Step (BYTE): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Step : BYTE := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Step : BYTE := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Step := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Step : BYTE; // 초기값 없음!

✅ 안전: Step : BYTE := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:23

설명: Intensity_Real_Data (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Intensity_Real_Data : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Intensity_Real_Data : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Intensity_Real_Data := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Intensity_Real_Data : REAL; // 초기값 없음!

✅ 안전: Intensity_Real_Data : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:25

설명: i (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : INT; // 초기값 없음!

✅ 안전: i : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:26

설명: K (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   K : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       K : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       K := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: K : INT; // 초기값 없음!

✅ 안전: K : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:7

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:8

설명: Loop (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Loop : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Loop : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Loop := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Loop : UINT; // 초기값 없음!

✅ 안전: Loop : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:9

설명: Count_StopZone (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Count_StopZone : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Count_StopZone : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Count_StopZone := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Count_StopZone : UINT; // 초기값 없음!

✅ 안전: Count_StopZone : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:10

설명: Count_Try (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Count_Try : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Count_Try : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Count_Try := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Count_Try : UINT; // 초기값 없음!

✅ 안전: Count_Try : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:17

설명: k (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   k : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       k : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       k := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: k : UINT; // 초기값 없음!

✅ 안전: k : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:18

설명: c (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   c : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       c : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       c := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: c : UINT; // 초기값 없음!

✅ 안전: c : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:23

설명: manualMode (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   manualMode : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       manualMode : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       manualMode := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: manualMode : BOOL; // 초기값 없음!

✅ 안전: manualMode : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:24

설명: paramResult (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   paramResult : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       paramResult : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       paramResult := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: paramResult : BOOL; // 초기값 없음!

✅ 안전: paramResult : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:8

설명: TempLimit_Min (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   TempLimit_Min : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       TempLimit_Min : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       TempLimit_Min := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: TempLimit_Min : REAL; // 초기값 없음!

✅ 안전: TempLimit_Min : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:9

설명: TempLimit_Max (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   TempLimit_Max : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       TempLimit_Max : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       TempLimit_Max := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: TempLimit_Max : REAL; // 초기값 없음!

✅ 안전: TempLimit_Max : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:14

설명: Alarm_Limit_Dev (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Alarm_Limit_Dev : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Alarm_Limit_Dev : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Alarm_Limit_Dev := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Alarm_Limit_Dev : REAL; // 초기값 없음!

✅ 안전: Alarm_Limit_Dev : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:29

설명: Count (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Count : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Count : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Count := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Count : UINT; // 초기값 없음!

✅ 안전: Count : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:37

설명: Save_Range (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Save_Range : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Save_Range : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Save_Range := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Save_Range : REAL; // 초기값 없음!

✅ 안전: Save_Range : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:40

설명: paramResult (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   paramResult : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       paramResult : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       paramResult := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: paramResult : BOOL; // 초기값 없음!

✅ 안전: paramResult : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:7

설명: Loop (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Loop : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Loop : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Loop := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Loop : UINT; // 초기값 없음!

✅ 안전: Loop : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:14

설명: manualMode (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   manualMode : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       manualMode : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       manualMode := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: manualMode : BOOL; // 초기값 없음!

✅ 안전: manualMode : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:15

설명: paramResult (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   paramResult : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       paramResult : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       paramResult := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: paramResult : BOOL; // 초기값 없음!

✅ 안전: paramResult : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:16

설명: Duplication_Step_Count (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Duplication_Step_Count : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Duplication_Step_Count : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Duplication_Step_Count := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Duplication_Step_Count : UINT; // 초기값 없음!

✅ 안전: Duplication_Step_Count : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:37

설명: Sum_S6_Flow_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sum_S6_Flow_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sum_S6_Flow_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sum_S6_Flow_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sum_S6_Flow_Set : REAL; // 초기값 없음!

✅ 안전: Sum_S6_Flow_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:38

설명: Sum_S4_Flow_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sum_S4_Flow_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sum_S4_Flow_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sum_S4_Flow_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sum_S4_Flow_Set : REAL; // 초기값 없음!

✅ 안전: Sum_S4_Flow_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:39

설명: Sum_H2_Flow_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sum_H2_Flow_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sum_H2_Flow_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sum_H2_Flow_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sum_H2_Flow_Set : REAL; // 초기값 없음!

✅ 안전: Sum_H2_Flow_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:40

설명: Sum_P1_Flow_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sum_P1_Flow_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sum_P1_Flow_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sum_P1_Flow_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sum_P1_Flow_Set : REAL; // 초기값 없음!

✅ 안전: Sum_P1_Flow_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:41

설명: Sum_P2_Flow_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sum_P2_Flow_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sum_P2_Flow_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sum_P2_Flow_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sum_P2_Flow_Set : REAL; // 초기값 없음!

✅ 안전: Sum_P2_Flow_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:42

설명: Sum_F2_Flow_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sum_F2_Flow_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sum_F2_Flow_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sum_F2_Flow_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sum_F2_Flow_Set : REAL; // 초기값 없음!

✅ 안전: Sum_F2_Flow_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:43

설명: Sum_DIPAS_Flow_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sum_DIPAS_Flow_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sum_DIPAS_Flow_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sum_DIPAS_Flow_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sum_DIPAS_Flow_Set : REAL; // 초기값 없음!

✅ 안전: Sum_DIPAS_Flow_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:44

설명: Sum_N2_Flow_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sum_N2_Flow_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sum_N2_Flow_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sum_N2_Flow_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sum_N2_Flow_Set : REAL; // 초기값 없음!

✅ 안전: Sum_N2_Flow_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:45

설명: Sum_NDU_Taget_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sum_NDU_Taget_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sum_NDU_Taget_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sum_NDU_Taget_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sum_NDU_Taget_Set : REAL; // 초기값 없음!

✅ 안전: Sum_NDU_Taget_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:47

설명: Sub_Sum_S6_Flow_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_Sum_S6_Flow_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_Sum_S6_Flow_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_Sum_S6_Flow_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_Sum_S6_Flow_Set : REAL; // 초기값 없음!

✅ 안전: Sub_Sum_S6_Flow_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:48

설명: Sub_Sum_S4_Flow_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_Sum_S4_Flow_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_Sum_S4_Flow_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_Sum_S4_Flow_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_Sum_S4_Flow_Set : REAL; // 초기값 없음!

✅ 안전: Sub_Sum_S4_Flow_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:49

설명: Sub_Sum_H2_Flow_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_Sum_H2_Flow_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_Sum_H2_Flow_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_Sum_H2_Flow_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_Sum_H2_Flow_Set : REAL; // 초기값 없음!

✅ 안전: Sub_Sum_H2_Flow_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:50

설명: Sub_Sum_P1_Flow_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_Sum_P1_Flow_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_Sum_P1_Flow_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_Sum_P1_Flow_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_Sum_P1_Flow_Set : REAL; // 초기값 없음!

✅ 안전: Sub_Sum_P1_Flow_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:51

설명: Sub_Sum_P2_Flow_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_Sum_P2_Flow_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_Sum_P2_Flow_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_Sum_P2_Flow_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_Sum_P2_Flow_Set : REAL; // 초기값 없음!

✅ 안전: Sub_Sum_P2_Flow_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:52

설명: Sub_Sum_F2_Flow_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_Sum_F2_Flow_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_Sum_F2_Flow_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_Sum_F2_Flow_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_Sum_F2_Flow_Set : REAL; // 초기값 없음!

✅ 안전: Sub_Sum_F2_Flow_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:53

설명: Sub_Sum_DIPAS_Flow_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_Sum_DIPAS_Flow_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_Sum_DIPAS_Flow_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_Sum_DIPAS_Flow_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_Sum_DIPAS_Flow_Set : REAL; // 초기값 없음!

✅ 안전: Sub_Sum_DIPAS_Flow_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:54

설명: Sub_Sum_N2_Flow_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_Sum_N2_Flow_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_Sum_N2_Flow_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_Sum_N2_Flow_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_Sum_N2_Flow_Set : REAL; // 초기값 없음!

✅ 안전: Sub_Sum_N2_Flow_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:55

설명: Sub_Sum_NDU_Taget_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_Sum_NDU_Taget_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_Sum_NDU_Taget_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_Sum_NDU_Taget_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_Sum_NDU_Taget_Set : REAL; // 초기값 없음!

✅ 안전: Sub_Sum_NDU_Taget_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:86

설명: paramResult (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   paramResult : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       paramResult : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       paramResult := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: paramResult : BOOL; // 초기값 없음!

✅ 안전: paramResult : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:96

설명: CycleNextStep (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   CycleNextStep : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       CycleNextStep : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       CycleNextStep := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: CycleNextStep : UINT; // 초기값 없음!

✅ 안전: CycleNextStep : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:112

설명: Mon_Check_Time (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Mon_Check_Time : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Mon_Check_Time : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Mon_Check_Time := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Mon_Check_Time : UDINT; // 초기값 없음!

✅ 안전: Mon_Check_Time : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:113

설명: Mon_Check_Value (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Mon_Check_Value : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Mon_Check_Value : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Mon_Check_Value := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Mon_Check_Value : UINT; // 초기값 없음!

✅ 안전: Mon_Check_Value : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:115

설명: Sub_Mon_Check_Time (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_Mon_Check_Time : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_Mon_Check_Time : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_Mon_Check_Time := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_Mon_Check_Time : UDINT; // 초기값 없음!

✅ 안전: Sub_Mon_Check_Time : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:116

설명: Sub_Mon_Check_Value (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_Mon_Check_Value : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_Mon_Check_Value : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_Mon_Check_Value := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_Mon_Check_Value : UINT; // 초기값 없음!

✅ 안전: Sub_Mon_Check_Value : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:132

설명: Gas_Loop (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Gas_Loop : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Gas_Loop : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Gas_Loop := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Gas_Loop : UINT; // 초기값 없음!

✅ 안전: Gas_Loop : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:133

설명: Gas_Loop1 (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Gas_Loop1 : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Gas_Loop1 : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Gas_Loop1 := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Gas_Loop1 : UINT; // 초기값 없음!

✅ 안전: Gas_Loop1 : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:140

설명: DelayTime (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DelayTime : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DelayTime : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DelayTime := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DelayTime : UDINT; // 초기값 없음!

✅ 안전: DelayTime : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:141

설명: CheckTime (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   CheckTime : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       CheckTime : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       CheckTime := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: CheckTime : UDINT; // 초기값 없음!

✅ 안전: CheckTime : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:142

설명: EndTime (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   EndTime : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       EndTime : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       EndTime := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: EndTime : UDINT; // 초기값 없음!

✅ 안전: EndTime : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:143

설명: Temp_Min (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Temp_Min : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Temp_Min : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Temp_Min := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Temp_Min : REAL; // 초기값 없음!

✅ 안전: Temp_Min : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:144

설명: Temp_Max (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Temp_Max : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Temp_Max : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Temp_Max := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Temp_Max : REAL; // 초기값 없음!

✅ 안전: Temp_Max : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:148

설명: Temp_End_Target_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Temp_End_Target_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Temp_End_Target_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Temp_End_Target_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Temp_End_Target_Value : REAL; // 초기값 없음!

✅ 안전: Temp_End_Target_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:150

설명: Sub_DelayTime (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_DelayTime : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_DelayTime : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_DelayTime := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_DelayTime : UDINT; // 초기값 없음!

✅ 안전: Sub_DelayTime : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:151

설명: Sub_CheckTime (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_CheckTime : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_CheckTime : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_CheckTime := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_CheckTime : UDINT; // 초기값 없음!

✅ 안전: Sub_CheckTime : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:152

설명: Sub_EndTime (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_EndTime : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_EndTime : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_EndTime := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_EndTime : UDINT; // 초기값 없음!

✅ 안전: Sub_EndTime : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:153

설명: Sub_Temp_Min (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_Temp_Min : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_Temp_Min : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_Temp_Min := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_Temp_Min : REAL; // 초기값 없음!

✅ 안전: Sub_Temp_Min : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:154

설명: Sub_Temp_Max (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_Temp_Max : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_Temp_Max : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_Temp_Max := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_Temp_Max : REAL; // 초기값 없음!

✅ 안전: Sub_Temp_Max : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:158

설명: Sub_Temp_End_Target_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_Temp_End_Target_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_Temp_End_Target_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_Temp_End_Target_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_Temp_End_Target_Value : REAL; // 초기값 없음!

✅ 안전: Sub_Temp_End_Target_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:210

설명: Sub_CycleNextStep (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Sub_CycleNextStep : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Sub_CycleNextStep : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Sub_CycleNextStep := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Sub_CycleNextStep : UINT; // 초기값 없음!

✅ 안전: Sub_CycleNextStep : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:258

설명: DColl_Data_Step_Number (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DColl_Data_Step_Number : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DColl_Data_Step_Number : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DColl_Data_Step_Number := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DColl_Data_Step_Number : UINT; // 초기값 없음!

✅ 안전: DColl_Data_Step_Number : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:260

설명: DColl_Data_Step_Time (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DColl_Data_Step_Time : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DColl_Data_Step_Time : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DColl_Data_Step_Time := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DColl_Data_Step_Time : UDINT; // 초기값 없음!

✅ 안전: DColl_Data_Step_Time : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:375

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:376

설명: k (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   k : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       k : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       k := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: k : UINT; // 초기값 없음!

✅ 안전: k : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:378

설명: Find_Buffer (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Find_Buffer : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Find_Buffer : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Find_Buffer := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Find_Buffer : UINT; // 초기값 없음!

✅ 안전: Find_Buffer : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:397

설명: fRatioSet (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fRatioSet : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fRatioSet : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fRatioSet := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fRatioSet : REAL; // 초기값 없음!

✅ 안전: fRatioSet : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:7

설명: Loop (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Loop : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Loop : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Loop := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Loop : UINT; // 초기값 없음!

✅ 안전: Loop : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:18

설명: paramResult (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   paramResult : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       paramResult : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       paramResult := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: paramResult : BOOL; // 초기값 없음!

✅ 안전: paramResult : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:23

설명: Check_Wafer (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Check_Wafer : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Check_Wafer : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Check_Wafer := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Check_Wafer : BOOL; // 초기값 없음!

✅ 안전: Check_Wafer : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:29

설명: Wafer_Charge_Check (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Wafer_Charge_Check : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Wafer_Charge_Check : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Wafer_Charge_Check := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Wafer_Charge_Check : BOOL; // 초기값 없음!

✅ 안전: Wafer_Charge_Check : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:34

설명: tHeater_Off_IO (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   tHeater_Off_IO : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       tHeater_Off_IO : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       tHeater_Off_IO := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: tHeater_Off_IO : BOOL; // 초기값 없음!

✅ 안전: tHeater_Off_IO : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:35

설명: tHeater_On_IO (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   tHeater_On_IO : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       tHeater_On_IO : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       tHeater_On_IO := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: tHeater_On_IO : BOOL; // 초기값 없음!

✅ 안전: tHeater_On_IO : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:42

설명: STS_Check (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   STS_Check : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       STS_Check : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       STS_Check := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: STS_Check : BOOL; // 초기값 없음!

✅ 안전: STS_Check : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:45

설명: tSub_Heater_On_IO (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   tSub_Heater_On_IO : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       tSub_Heater_On_IO : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       tSub_Heater_On_IO := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: tSub_Heater_On_IO : BOOL; // 초기값 없음!

✅ 안전: tSub_Heater_On_IO : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:51

설명: tCap_Heater_On_IO (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   tCap_Heater_On_IO : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       tCap_Heater_On_IO : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       tCap_Heater_On_IO := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: tCap_Heater_On_IO : BOOL; // 초기값 없음!

✅ 안전: tCap_Heater_On_IO : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:57

설명: tLine_Heater_On_IO (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   tLine_Heater_On_IO : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       tLine_Heater_On_IO : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       tLine_Heater_On_IO := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: tLine_Heater_On_IO : BOOL; // 초기값 없음!

✅ 안전: tLine_Heater_On_IO : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:62

설명: bX20_Error (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bX20_Error : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bX20_Error : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bX20_Error := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bX20_Error : BOOL; // 초기값 없음!

✅ 안전: bX20_Error : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:63

설명: bHeater_Off_ELB (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bHeater_Off_ELB : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bHeater_Off_ELB : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bHeater_Off_ELB := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bHeater_Off_ELB : BOOL; // 초기값 없음!

✅ 안전: bHeater_Off_ELB : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:64

설명: bHeater_Off_SCR (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bHeater_Off_SCR : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bHeater_Off_SCR : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bHeater_Off_SCR := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bHeater_Off_SCR : BOOL; // 초기값 없음!

✅ 안전: bHeater_Off_SCR : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:65

설명: bHeater_Off_Temp (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bHeater_Off_Temp : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bHeater_Off_Temp : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bHeater_Off_Temp := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bHeater_Off_Temp : BOOL; // 초기값 없음!

✅ 안전: bHeater_Off_Temp : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:66

설명: bHeater_Off_Door (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bHeater_Off_Door : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bHeater_Off_Door : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bHeater_Off_Door := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bHeater_Off_Door : BOOL; // 초기값 없음!

✅ 안전: bHeater_Off_Door : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:67

설명: bHeater_Off_Leak (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bHeater_Off_Leak : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bHeater_Off_Leak : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bHeater_Off_Leak := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bHeater_Off_Leak : BOOL; // 초기값 없음!

✅ 안전: bHeater_Off_Leak : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:72

설명: Module_Count (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Module_Count : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Module_Count : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Module_Count := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Module_Count : INT; // 초기값 없음!

✅ 안전: Module_Count : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:73

설명: MFC_Alarm_Offset (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   MFC_Alarm_Offset : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       MFC_Alarm_Offset : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       MFC_Alarm_Offset := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: MFC_Alarm_Offset : INT; // 초기값 없음!

✅ 안전: MFC_Alarm_Offset : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:75

설명: bError (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bError : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bError : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bError := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bError : BOOL; // 초기값 없음!

✅ 안전: bError : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:82

설명: Zone (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Zone : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Zone : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Zone := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Zone : UINT; // 초기값 없음!

✅ 안전: Zone : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:83

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:84

설명: j (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   j : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       j : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       j := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: j : UINT; // 초기값 없음!

✅ 안전: j : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:99

설명: N2_Flow_Sum (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   N2_Flow_Sum : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       N2_Flow_Sum : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       N2_Flow_Sum := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: N2_Flow_Sum : REAL; // 초기값 없음!

✅ 안전: N2_Flow_Sum : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:109

설명: APC_Warning (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   APC_Warning : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       APC_Warning : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       APC_Warning := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: APC_Warning : REAL; // 초기값 없음!

✅ 안전: APC_Warning : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:110

설명: APC_Hazard (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   APC_Hazard : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       APC_Hazard : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       APC_Hazard := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: APC_Hazard : REAL; // 초기값 없음!

✅ 안전: APC_Hazard : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:112

설명: APC_Limit (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   APC_Limit : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       APC_Limit : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       APC_Limit := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: APC_Limit : REAL; // 초기값 없음!

✅ 안전: APC_Limit : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:114

설명: ALARM_Data (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   ALARM_Data : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       ALARM_Data : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       ALARM_Data := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: ALARM_Data : UINT; // 초기값 없음!

✅ 안전: ALARM_Data : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:115

설명: Buffer_Data (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Buffer_Data : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Buffer_Data : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Buffer_Data := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Buffer_Data : UINT; // 초기값 없음!

✅ 안전: Buffer_Data : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:121

설명: Data_Change_Value (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Data_Change_Value : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Data_Change_Value : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Data_Change_Value := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Data_Change_Value : UINT; // 초기값 없음!

✅ 안전: Data_Change_Value : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:224

설명: Buff_Temp (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Buff_Temp : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Buff_Temp : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Buff_Temp := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Buff_Temp : REAL; // 초기값 없음!

✅ 안전: Buff_Temp : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:225

설명: Buff_PUMP_RUN (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Buff_PUMP_RUN : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Buff_PUMP_RUN : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Buff_PUMP_RUN := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Buff_PUMP_RUN : BOOL; // 초기값 없음!

✅ 안전: Buff_PUMP_RUN : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:226

설명: Buff_Scrubber (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Buff_Scrubber : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Buff_Scrubber : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Buff_Scrubber := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Buff_Scrubber : BOOL; // 초기값 없음!

✅ 안전: Buff_Scrubber : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:228

설명: GAS_H2_FLOW (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   GAS_H2_FLOW : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       GAS_H2_FLOW : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       GAS_H2_FLOW := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: GAS_H2_FLOW : BOOL; // 초기값 없음!

✅ 안전: GAS_H2_FLOW : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:229

설명: SUM_H2_MFC_FLOW (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SUM_H2_MFC_FLOW : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SUM_H2_MFC_FLOW : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SUM_H2_MFC_FLOW := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SUM_H2_MFC_FLOW : REAL; // 초기값 없음!

✅ 안전: SUM_H2_MFC_FLOW : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:230

설명: SUM_H2_MFC_SET (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SUM_H2_MFC_SET : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SUM_H2_MFC_SET : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SUM_H2_MFC_SET := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SUM_H2_MFC_SET : REAL; // 초기값 없음!

✅ 안전: SUM_H2_MFC_SET : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:232

설명: GAS_S4_FLOW (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   GAS_S4_FLOW : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       GAS_S4_FLOW : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       GAS_S4_FLOW := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: GAS_S4_FLOW : BOOL; // 초기값 없음!

✅ 안전: GAS_S4_FLOW : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:233

설명: SUM_S4_MFC_FLOW (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SUM_S4_MFC_FLOW : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SUM_S4_MFC_FLOW : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SUM_S4_MFC_FLOW := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SUM_S4_MFC_FLOW : REAL; // 초기값 없음!

✅ 안전: SUM_S4_MFC_FLOW : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:234

설명: SUM_S4_MFC_SET (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SUM_S4_MFC_SET : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SUM_S4_MFC_SET : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SUM_S4_MFC_SET := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SUM_S4_MFC_SET : REAL; // 초기값 없음!

✅ 안전: SUM_S4_MFC_SET : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:236

설명: GAS_S6_FLOW (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   GAS_S6_FLOW : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       GAS_S6_FLOW : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       GAS_S6_FLOW := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: GAS_S6_FLOW : BOOL; // 초기값 없음!

✅ 안전: GAS_S6_FLOW : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:237

설명: SUM_S6_MFC_FLOW (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SUM_S6_MFC_FLOW : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SUM_S6_MFC_FLOW : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SUM_S6_MFC_FLOW := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SUM_S6_MFC_FLOW : REAL; // 초기값 없음!

✅ 안전: SUM_S6_MFC_FLOW : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:238

설명: SUM_S6_MFC_SET (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SUM_S6_MFC_SET : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SUM_S6_MFC_SET : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SUM_S6_MFC_SET := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SUM_S6_MFC_SET : REAL; // 초기값 없음!

✅ 안전: SUM_S6_MFC_SET : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:240

설명: GAS_P1_FLOW (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   GAS_P1_FLOW : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       GAS_P1_FLOW : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       GAS_P1_FLOW := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: GAS_P1_FLOW : BOOL; // 초기값 없음!

✅ 안전: GAS_P1_FLOW : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:241

설명: SUM_P1_MFC_FLOW (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SUM_P1_MFC_FLOW : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SUM_P1_MFC_FLOW : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SUM_P1_MFC_FLOW := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SUM_P1_MFC_FLOW : REAL; // 초기값 없음!

✅ 안전: SUM_P1_MFC_FLOW : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:242

설명: SUM_P1_MFC_SET (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SUM_P1_MFC_SET : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SUM_P1_MFC_SET : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SUM_P1_MFC_SET := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SUM_P1_MFC_SET : REAL; // 초기값 없음!

✅ 안전: SUM_P1_MFC_SET : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:244

설명: GAS_P2_FLOW (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   GAS_P2_FLOW : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       GAS_P2_FLOW : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       GAS_P2_FLOW := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: GAS_P2_FLOW : BOOL; // 초기값 없음!

✅ 안전: GAS_P2_FLOW : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:245

설명: SUM_P2_MFC_FLOW (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SUM_P2_MFC_FLOW : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SUM_P2_MFC_FLOW : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SUM_P2_MFC_FLOW := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SUM_P2_MFC_FLOW : REAL; // 초기값 없음!

✅ 안전: SUM_P2_MFC_FLOW : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:246

설명: SUM_P2_MFC_SET (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SUM_P2_MFC_SET : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SUM_P2_MFC_SET : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SUM_P2_MFC_SET := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SUM_P2_MFC_SET : REAL; // 초기값 없음!

✅ 안전: SUM_P2_MFC_SET : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:248

설명: GAS_F2_FLOW (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   GAS_F2_FLOW : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       GAS_F2_FLOW : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       GAS_F2_FLOW := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: GAS_F2_FLOW : BOOL; // 초기값 없음!

✅ 안전: GAS_F2_FLOW : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:249

설명: SUM_F2_MFC_FLOW (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SUM_F2_MFC_FLOW : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SUM_F2_MFC_FLOW : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SUM_F2_MFC_FLOW := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SUM_F2_MFC_FLOW : REAL; // 초기값 없음!

✅ 안전: SUM_F2_MFC_FLOW : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:250

설명: SUM_F2_MFC_SET (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SUM_F2_MFC_SET : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SUM_F2_MFC_SET : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SUM_F2_MFC_SET := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SUM_F2_MFC_SET : REAL; // 초기값 없음!

✅ 안전: SUM_F2_MFC_SET : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:252

설명: GAS_DIPAS_FLOW (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   GAS_DIPAS_FLOW : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       GAS_DIPAS_FLOW : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       GAS_DIPAS_FLOW := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: GAS_DIPAS_FLOW : BOOL; // 초기값 없음!

✅ 안전: GAS_DIPAS_FLOW : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:253

설명: SUM_DIPAS_MFC_FLOW (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SUM_DIPAS_MFC_FLOW : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SUM_DIPAS_MFC_FLOW : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SUM_DIPAS_MFC_FLOW := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SUM_DIPAS_MFC_FLOW : REAL; // 초기값 없음!

✅ 안전: SUM_DIPAS_MFC_FLOW : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:254

설명: SUM_DIPAS_MFC_SET (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SUM_DIPAS_MFC_SET : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SUM_DIPAS_MFC_SET : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SUM_DIPAS_MFC_SET := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SUM_DIPAS_MFC_SET : REAL; // 초기값 없음!

✅ 안전: SUM_DIPAS_MFC_SET : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:256

설명: TAGET_NDU_FLOW (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   TAGET_NDU_FLOW : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       TAGET_NDU_FLOW : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       TAGET_NDU_FLOW := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: TAGET_NDU_FLOW : REAL; // 초기값 없음!

✅ 안전: TAGET_NDU_FLOW : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:257

설명: TAGET_NDU_SET (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   TAGET_NDU_SET : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       TAGET_NDU_SET : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       TAGET_NDU_SET := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: TAGET_NDU_SET : REAL; // 초기값 없음!

✅ 안전: TAGET_NDU_SET : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:259

설명: SUM_NDU_MFC_FLOW (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SUM_NDU_MFC_FLOW : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SUM_NDU_MFC_FLOW : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SUM_NDU_MFC_FLOW := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SUM_NDU_MFC_FLOW : REAL; // 초기값 없음!

✅ 안전: SUM_NDU_MFC_FLOW : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:260

설명: SUM_NDU_MFC_SET (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SUM_NDU_MFC_SET : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SUM_NDU_MFC_SET : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SUM_NDU_MFC_SET := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SUM_NDU_MFC_SET : REAL; // 초기값 없음!

✅ 안전: SUM_NDU_MFC_SET : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:289

설명: H2_Flow (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   H2_Flow : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       H2_Flow : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       H2_Flow := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: H2_Flow : REAL; // 초기값 없음!

✅ 안전: H2_Flow : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:290

설명: O2_Flow (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   O2_Flow : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       O2_Flow : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       O2_Flow := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: O2_Flow : REAL; // 초기값 없음!

✅ 안전: O2_Flow : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:291

설명: H2_O2_Flow_Ratio (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   H2_O2_Flow_Ratio : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       H2_O2_Flow_Ratio : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       H2_O2_Flow_Ratio := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: H2_O2_Flow_Ratio : REAL; // 초기값 없음!

✅ 안전: H2_O2_Flow_Ratio : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:292

설명: H2_O2_Ratio_STS (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   H2_O2_Ratio_STS : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       H2_O2_Ratio_STS : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       H2_O2_Ratio_STS := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: H2_O2_Ratio_STS : BOOL; // 초기값 없음!

✅ 안전: H2_O2_Ratio_STS : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:303

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:310

설명: DO_APC_PUMP_RUNING (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DO_APC_PUMP_RUNING : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DO_APC_PUMP_RUNING : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DO_APC_PUMP_RUNING := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DO_APC_PUMP_RUNING : INT; // 초기값 없음!

✅ 안전: DO_APC_PUMP_RUNING : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:312

설명: AV68_Open_Flag (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AV68_Open_Flag : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AV68_Open_Flag : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AV68_Open_Flag := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AV68_Open_Flag : BOOL; // 초기값 없음!

✅ 안전: AV68_Open_Flag : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:313

설명: HFV05_Open_Flag (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   HFV05_Open_Flag : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       HFV05_Open_Flag : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       HFV05_Open_Flag := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: HFV05_Open_Flag : BOOL; // 초기값 없음!

✅ 안전: HFV05_Open_Flag : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:18

설명: SlowRate_Con (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SlowRate_Con : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SlowRate_Con : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SlowRate_Con := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SlowRate_Con : LREAL; // 초기값 없음!

✅ 안전: SlowRate_Con : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:22

설명: i (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : BOOL; // 초기값 없음!

✅ 안전: i : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:27

설명: Leak_Min_Count (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Leak_Min_Count : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Leak_Min_Count : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Leak_Min_Count := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Leak_Min_Count : UINT; // 초기값 없음!

✅ 안전: Leak_Min_Count : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:41

설명: Leak_Start (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Leak_Start : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Leak_Start : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Leak_Start := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Leak_Start : REAL; // 초기값 없음!

✅ 안전: Leak_Start : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:42

설명: Leak_End (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Leak_End : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Leak_End : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Leak_End := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Leak_End : REAL; // 초기값 없음!

✅ 안전: Leak_End : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:43

설명: Leak_Rate (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Leak_Rate : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Leak_Rate : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Leak_Rate := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Leak_Rate : REAL; // 초기값 없음!

✅ 안전: Leak_Rate : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:44

설명: Leak_Count (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Leak_Count : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Leak_Count : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Leak_Count := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Leak_Count : INT; // 초기값 없음!

✅ 안전: Leak_Count : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:46

설명: VG01_Start_Stable_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   VG01_Start_Stable_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       VG01_Start_Stable_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       VG01_Start_Stable_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: VG01_Start_Stable_Pressure : REAL; // 초기값 없음!

✅ 안전: VG01_Start_Stable_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:47

설명: VG01_Start_End_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   VG01_Start_End_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       VG01_Start_End_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       VG01_Start_End_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: VG01_Start_End_Pressure : REAL; // 초기값 없음!

✅ 안전: VG01_Start_End_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:48

설명: VG02_Start_Stable_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   VG02_Start_Stable_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       VG02_Start_Stable_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       VG02_Start_Stable_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: VG02_Start_Stable_Pressure : REAL; // 초기값 없음!

✅ 안전: VG02_Start_Stable_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:49

설명: VG02_Start_End_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   VG02_Start_End_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       VG02_Start_End_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       VG02_Start_End_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: VG02_Start_End_Pressure : REAL; // 초기값 없음!

✅ 안전: VG02_Start_End_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:51

설명: it (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   it : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       it : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       it := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: it : UINT; // 초기값 없음!

✅ 안전: it : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:52

설명: Loop (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Loop : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Loop : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Loop := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Loop : REAL; // 초기값 없음!

✅ 안전: Loop : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:53

설명: Pressure_Mode (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Pressure_Mode : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Pressure_Mode : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Pressure_Mode := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Pressure_Mode : INT; // 초기값 없음!

✅ 안전: Pressure_Mode : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:57

설명: Temp_VG01_Cal_Accumulate_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Temp_VG01_Cal_Accumulate_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Temp_VG01_Cal_Accumulate_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Temp_VG01_Cal_Accumulate_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Temp_VG01_Cal_Accumulate_Value : REAL; // 초기값 없음!

✅ 안전: Temp_VG01_Cal_Accumulate_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:58

설명: Temp_VG02_Cal_Accumulate_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Temp_VG02_Cal_Accumulate_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Temp_VG02_Cal_Accumulate_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Temp_VG02_Cal_Accumulate_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Temp_VG02_Cal_Accumulate_Value : REAL; // 초기값 없음!

✅ 안전: Temp_VG02_Cal_Accumulate_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:7

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:35

설명: iBoatSpeed (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iBoatSpeed : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iBoatSpeed : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iBoatSpeed := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iBoatSpeed : INT; // 초기값 없음!

✅ 안전: iBoatSpeed : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:36

설명: rBoatSpeed (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rBoatSpeed : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rBoatSpeed : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rBoatSpeed := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rBoatSpeed : REAL; // 초기값 없음!

✅ 안전: rBoatSpeed : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:8

설명: Step (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Step : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Step : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Step := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Step : UINT; // 초기값 없음!

✅ 안전: Step : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:11

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:12

설명: loop (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   loop : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       loop : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       loop := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: loop : UINT; // 초기값 없음!

✅ 안전: loop : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:28

설명: TV_Low_Limit (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   TV_Low_Limit : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       TV_Low_Limit : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       TV_Low_Limit := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: TV_Low_Limit : REAL; // 초기값 없음!

✅ 안전: TV_Low_Limit : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:29

설명: TV_High_Limit (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   TV_High_Limit : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       TV_High_Limit : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       TV_High_Limit := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: TV_High_Limit : REAL; // 초기값 없음!

✅ 안전: TV_High_Limit : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:30

설명: TV_P (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   TV_P : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       TV_P : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       TV_P := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: TV_P : REAL; // 초기값 없음!

✅ 안전: TV_P : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:31

설명: TV_I (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   TV_I : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       TV_I : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       TV_I := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: TV_I : REAL; // 초기값 없음!

✅ 안전: TV_I : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:32

설명: TV_D (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   TV_D : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       TV_D : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       TV_D := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: TV_D : REAL; // 초기값 없음!

✅ 안전: TV_D : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:33

설명: TV_T (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   TV_T : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       TV_T : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       TV_T := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: TV_T : REAL; // 초기값 없음!

✅ 안전: TV_T : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:18

설명: Open_Status (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Open_Status : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Open_Status : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Open_Status := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Open_Status : BOOL; // 초기값 없음!

✅ 안전: Open_Status : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:19

설명: Close_Status (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Close_Status : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Close_Status : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Close_Status := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Close_Status : BOOL; // 초기값 없음!

✅ 안전: Close_Status : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:20

설명: Cycle_Count (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Cycle_Count : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Cycle_Count : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Cycle_Count := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Cycle_Count : UINT; // 초기값 없음!

✅ 안전: Cycle_Count : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:22

설명: Buff_Temp_Center_Zone (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Buff_Temp_Center_Zone : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Buff_Temp_Center_Zone : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Buff_Temp_Center_Zone := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Buff_Temp_Center_Zone : REAL; // 초기값 없음!

✅ 안전: Buff_Temp_Center_Zone : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:23

설명: iCenter_Zone (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   iCenter_Zone : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       iCenter_Zone : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       iCenter_Zone := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: iCenter_Zone : UINT; // 초기값 없음!

✅ 안전: iCenter_Zone : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:12

설명: Simulation (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Simulation : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Simulation : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Simulation := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Simulation : INT; // 초기값 없음!

✅ 안전: Simulation : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:14

설명: bDeviation_Value_Low (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bDeviation_Value_Low : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bDeviation_Value_Low : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bDeviation_Value_Low := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bDeviation_Value_Low : BOOL; // 초기값 없음!

✅ 안전: bDeviation_Value_Low : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:15

설명: bDeviation_Value_High (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bDeviation_Value_High : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bDeviation_Value_High : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bDeviation_Value_High := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bDeviation_Value_High : BOOL; // 초기값 없음!

✅ 안전: bDeviation_Value_High : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:9

설명: Config_RSD_Position (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Config_RSD_Position : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Config_RSD_Position : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Config_RSD_Position := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Config_RSD_Position : REAL; // 초기값 없음!

✅ 안전: Config_RSD_Position : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:10

설명: Config_RSD_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Config_RSD_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Config_RSD_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Config_RSD_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Config_RSD_Pressure : REAL; // 초기값 없음!

✅ 안전: Config_RSD_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:16

설명: SlowRate_Con (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   SlowRate_Con : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       SlowRate_Con : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       SlowRate_Con := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: SlowRate_Con : LREAL; // 초기값 없음!

✅ 안전: SlowRate_Con : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:20

설명: cGuage_Unit (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   cGuage_Unit : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       cGuage_Unit : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       cGuage_Unit := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: cGuage_Unit : INT; // 초기값 없음!

✅ 안전: cGuage_Unit : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:31

설명: Leak_Start (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Leak_Start : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Leak_Start : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Leak_Start := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Leak_Start : REAL; // 초기값 없음!

✅ 안전: Leak_Start : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:32

설명: Leak_End (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Leak_End : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Leak_End : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Leak_End := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Leak_End : REAL; // 초기값 없음!

✅ 안전: Leak_End : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:33

설명: Leak_Rate (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Leak_Rate : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Leak_Rate : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Leak_Rate := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Leak_Rate : REAL; // 초기값 없음!

✅ 안전: Leak_Rate : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:34

설명: Leak_Count (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Leak_Count : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Leak_Count : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Leak_Count := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Leak_Count : REAL; // 초기값 없음!

✅ 안전: Leak_Count : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:12

설명: VG_Start_Stable_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   VG_Start_Stable_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       VG_Start_Stable_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       VG_Start_Stable_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: VG_Start_Stable_Pressure : REAL; // 초기값 없음!

✅ 안전: VG_Start_Stable_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:13

설명: VG_Start_End_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   VG_Start_End_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       VG_Start_End_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       VG_Start_End_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: VG_Start_End_Pressure : REAL; // 초기값 없음!

✅ 안전: VG_Start_End_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:14

설명: Temp_VG_Cal_Before (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Temp_VG_Cal_Before : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Temp_VG_Cal_Before : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Temp_VG_Cal_Before := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Temp_VG_Cal_Before : REAL; // 초기값 없음!

✅ 안전: Temp_VG_Cal_Before : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:12

설명: VG_Start_Stable_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   VG_Start_Stable_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       VG_Start_Stable_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       VG_Start_Stable_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: VG_Start_Stable_Pressure : REAL; // 초기값 없음!

✅ 안전: VG_Start_Stable_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:13

설명: VG_Start_End_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   VG_Start_End_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       VG_Start_End_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       VG_Start_End_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: VG_Start_End_Pressure : REAL; // 초기값 없음!

✅ 안전: VG_Start_End_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:14

설명: Temp_VG_Cal_Before (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Temp_VG_Cal_Before : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Temp_VG_Cal_Before : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Temp_VG_Cal_Before := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Temp_VG_Cal_Before : REAL; // 초기값 없음!

✅ 안전: Temp_VG_Cal_Before : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:12

설명: VG_Start_Stable_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   VG_Start_Stable_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       VG_Start_Stable_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       VG_Start_Stable_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: VG_Start_Stable_Pressure : REAL; // 초기값 없음!

✅ 안전: VG_Start_Stable_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:13

설명: VG_Start_End_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   VG_Start_End_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       VG_Start_End_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       VG_Start_End_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: VG_Start_End_Pressure : REAL; // 초기값 없음!

✅ 안전: VG_Start_End_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:14

설명: Temp_VG_Cal_Before (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Temp_VG_Cal_Before : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Temp_VG_Cal_Before : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Temp_VG_Cal_Before := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Temp_VG_Cal_Before : REAL; // 초기값 없음!

✅ 안전: Temp_VG_Cal_Before : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:12

설명: VG_Start_Stable_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   VG_Start_Stable_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       VG_Start_Stable_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       VG_Start_Stable_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: VG_Start_Stable_Pressure : REAL; // 초기값 없음!

✅ 안전: VG_Start_Stable_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:13

설명: VG_Start_End_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   VG_Start_End_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       VG_Start_End_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       VG_Start_End_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: VG_Start_End_Pressure : REAL; // 초기값 없음!

✅ 안전: VG_Start_End_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:14

설명: Temp_VG_Cal_Before (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Temp_VG_Cal_Before : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Temp_VG_Cal_Before : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Temp_VG_Cal_Before := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Temp_VG_Cal_Before : REAL; // 초기값 없음!

✅ 안전: Temp_VG_Cal_Before : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:12

설명: VG_Start_Stable_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   VG_Start_Stable_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       VG_Start_Stable_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       VG_Start_Stable_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: VG_Start_Stable_Pressure : REAL; // 초기값 없음!

✅ 안전: VG_Start_Stable_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:13

설명: VG_Start_End_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   VG_Start_End_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       VG_Start_End_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       VG_Start_End_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: VG_Start_End_Pressure : REAL; // 초기값 없음!

✅ 안전: VG_Start_End_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:14

설명: Temp_VG_Cal_Before (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Temp_VG_Cal_Before : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Temp_VG_Cal_Before : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Temp_VG_Cal_Before := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Temp_VG_Cal_Before : REAL; // 초기값 없음!

✅ 안전: Temp_VG_Cal_Before : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:2

설명: Loop (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Loop : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Loop : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Loop := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Loop : UINT; // 초기값 없음!

✅ 안전: Loop : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:14

설명: old_VG_Value (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   old_VG_Value : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       old_VG_Value : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       old_VG_Value := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: old_VG_Value : REAL; // 초기값 없음!

✅ 안전: old_VG_Value : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Input.TcPOU:2

설명: logCnt (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   logCnt : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       logCnt : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       logCnt := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: logCnt : UINT; // 초기값 없음!

✅ 안전: logCnt : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:4

설명: Config_Scale (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Config_Scale : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Config_Scale : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Config_Scale := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Config_Scale : REAL; // 초기값 없음!

✅ 안전: Config_Scale : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:12

설명: rAlarmLimit (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   rAlarmLimit : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       rAlarmLimit : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       rAlarmLimit := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: rAlarmLimit : REAL; // 초기값 없음!

✅ 안전: rAlarmLimit : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:13

설명: wAlarmLimit (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   wAlarmLimit : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       wAlarmLimit : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       wAlarmLimit := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: wAlarmLimit : REAL; // 초기값 없음!

✅ 안전: wAlarmLimit : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:3

설명: fInSetTemp (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fInSetTemp : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fInSetTemp : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fInSetTemp := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fInSetTemp : REAL; // 초기값 없음!

✅ 안전: fInSetTemp : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:4

설명: fInSpikeTC_PV (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fInSpikeTC_PV : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fInSpikeTC_PV : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fInSpikeTC_PV := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fInSpikeTC_PV : REAL; // 초기값 없음!

✅ 안전: fInSpikeTC_PV : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:5

설명: fInProfileTC_PV (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fInProfileTC_PV : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fInProfileTC_PV : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fInProfileTC_PV := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fInProfileTC_PV : REAL; // 초기값 없음!

✅ 안전: fInProfileTC_PV : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:6

설명: fInPowValue (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fInPowValue : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fInPowValue : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fInPowValue := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fInPowValue : REAL; // 초기값 없음!

✅ 안전: fInPowValue : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:12

설명: fOutRampValue (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fOutRampValue : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fOutRampValue : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fOutRampValue := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fOutRampValue : REAL; // 초기값 없음!

✅ 안전: fOutRampValue : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:13

설명: fOutRampCtrl (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fOutRampCtrl : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fOutRampCtrl : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fOutRampCtrl := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fOutRampCtrl : REAL; // 초기값 없음!

✅ 안전: fOutRampCtrl : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:14

설명: fOutPower (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fOutPower : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fOutPower : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fOutPower := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fOutPower : REAL; // 초기값 없음!

✅ 안전: fOutPower : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:15

설명: fMaxOvershoot (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fMaxOvershoot : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fMaxOvershoot : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fMaxOvershoot := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fMaxOvershoot : REAL; // 초기값 없음!

✅ 안전: fMaxOvershoot : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:18

설명: bError (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bError : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bError : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bError := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bError : BOOL; // 초기값 없음!

✅ 안전: bError : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:21

설명: fP_Out (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fP_Out : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fP_Out : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fP_Out := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fP_Out : REAL; // 초기값 없음!

✅ 안전: fP_Out : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:22

설명: fI_Out (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fI_Out : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fI_Out : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fI_Out := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fI_Out : REAL; // 초기값 없음!

✅ 안전: fI_Out : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:23

설명: fD_Out (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fD_Out : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fD_Out : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fD_Out := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fD_Out : REAL; // 초기값 없음!

✅ 안전: fD_Out : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:24

설명: fPID_Out (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fPID_Out : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fPID_Out : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fPID_Out := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fPID_Out : REAL; // 초기값 없음!

✅ 안전: fPID_Out : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:25

설명: bCAS_Tune (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bCAS_Tune : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bCAS_Tune : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bCAS_Tune := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bCAS_Tune : BOOL; // 초기값 없음!

✅ 안전: bCAS_Tune : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:26

설명: fCAS_Tune_Result (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fCAS_Tune_Result : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fCAS_Tune_Result : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fCAS_Tune_Result := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fCAS_Tune_Result : REAL; // 초기값 없음!

✅ 안전: fCAS_Tune_Result : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:27

설명: bACC_Tune (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bACC_Tune : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bACC_Tune : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bACC_Tune := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bACC_Tune : BOOL; // 초기값 없음!

✅ 안전: bACC_Tune : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:28

설명: fACC_RDNP_Result (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fACC_RDNP_Result : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fACC_RDNP_Result : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fACC_RDNP_Result := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fACC_RDNP_Result : REAL; // 초기값 없음!

✅ 안전: fACC_RDNP_Result : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:29

설명: fACC_SP_Lag_Result (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fACC_SP_Lag_Result : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fACC_SP_Lag_Result : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fACC_SP_Lag_Result := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fACC_SP_Lag_Result : REAL; // 초기값 없음!

✅ 안전: fACC_SP_Lag_Result : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:30

설명: fTV_Out_P (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fTV_Out_P : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fTV_Out_P : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fTV_Out_P := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fTV_Out_P : REAL; // 초기값 없음!

✅ 안전: fTV_Out_P : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:31

설명: fTV_Out_I (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fTV_Out_I : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fTV_Out_I : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fTV_Out_I := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fTV_Out_I : REAL; // 초기값 없음!

✅ 안전: fTV_Out_I : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:32

설명: fTV_Out_D (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fTV_Out_D : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fTV_Out_D : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fTV_Out_D := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fTV_Out_D : REAL; // 초기값 없음!

✅ 안전: fTV_Out_D : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:33

설명: fTV_Out_PID_Sum (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fTV_Out_PID_Sum : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fTV_Out_PID_Sum : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fTV_Out_PID_Sum := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fTV_Out_PID_Sum : REAL; // 초기값 없음!

✅ 안전: fTV_Out_PID_Sum : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:34

설명: fTV_Out_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fTV_Out_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fTV_Out_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fTV_Out_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fTV_Out_Set : REAL; // 초기값 없음!

✅ 안전: fTV_Out_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:38

설명: fManualPow (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fManualPow : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fManualPow : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fManualPow := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fManualPow : REAL; // 초기값 없음!

✅ 안전: fManualPow : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:39

설명: fPowBuff (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fPowBuff : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fPowBuff : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fPowBuff := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fPowBuff : REAL; // 초기값 없음!

✅ 안전: fPowBuff : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:2

설명: fInitTemp (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fInitTemp : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fInitTemp : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fInitTemp := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fInitTemp : LREAL; // 초기값 없음!

✅ 안전: fInitTemp : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:3

설명: fOut (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fOut : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fOut : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fOut := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fOut : LREAL; // 초기값 없음!

✅ 안전: fOut : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:4

설명: fKp (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fKp : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fKp : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fKp := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fKp : REAL; // 초기값 없음!

✅ 안전: fKp : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:10

설명: fValue (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fValue : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fValue : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fValue := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fValue : REAL; // 초기값 없음!

✅ 안전: fValue : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:20

설명: bParameterSet (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bParameterSet : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bParameterSet : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bParameterSet := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bParameterSet : BOOL; // 초기값 없음!

✅ 안전: bParameterSet : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:21

설명: bModBusError (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bModBusError : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bModBusError : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bModBusError := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bModBusError : BOOL; // 초기값 없음!

✅ 안전: bModBusError : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:22

설명: bSpike_TC_Sensor_Break (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bSpike_TC_Sensor_Break : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bSpike_TC_Sensor_Break : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bSpike_TC_Sensor_Break := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bSpike_TC_Sensor_Break : BOOL; // 초기값 없음!

✅ 안전: bSpike_TC_Sensor_Break : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:23

설명: bProfile_TC_Sensor_Break (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bProfile_TC_Sensor_Break : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bProfile_TC_Sensor_Break : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bProfile_TC_Sensor_Break := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bProfile_TC_Sensor_Break : BOOL; // 초기값 없음!

✅ 안전: bProfile_TC_Sensor_Break : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:24

설명: bOverTemp_TC_Sensor_Break (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bOverTemp_TC_Sensor_Break : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bOverTemp_TC_Sensor_Break : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bOverTemp_TC_Sensor_Break := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bOverTemp_TC_Sensor_Break : BOOL; // 초기값 없음!

✅ 안전: bOverTemp_TC_Sensor_Break : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:26

설명: i (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : INT; // 초기값 없음!

✅ 안전: i : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:27

설명: Step (BYTE): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Step : BYTE := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Step : BYTE := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Step := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Step : BYTE; // 초기값 없음!

✅ 안전: Step : BYTE := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:28

설명: Err_Count (WORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Err_Count : WORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Err_Count : WORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Err_Count := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Err_Count : WORD; // 초기값 없음!

✅ 안전: Err_Count : WORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:29

설명: bWriteRegs (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bWriteRegs : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bWriteRegs : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bWriteRegs := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bWriteRegs : BOOL; // 초기값 없음!

✅ 안전: bWriteRegs : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:30

설명: bErrorRegs (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bErrorRegs : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bErrorRegs : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bErrorRegs := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bErrorRegs : BOOL; // 초기값 없음!

✅ 안전: bErrorRegs : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:2

설명: bParameterSet (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bParameterSet : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bParameterSet : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bParameterSet := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bParameterSet : BOOL; // 초기값 없음!

✅ 안전: bParameterSet : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:3

설명: i (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : INT; // 초기값 없음!

✅ 안전: i : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:4

설명: Err_Count (WORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Err_Count : WORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Err_Count : WORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Err_Count := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Err_Count : WORD; // 초기값 없음!

✅ 안전: Err_Count : WORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:2

설명: i (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : INT; // 초기값 없음!

✅ 안전: i : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:3

설명: j (WORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   j : WORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       j : WORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       j := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: j : WORD; // 초기값 없음!

✅ 안전: j : WORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:4

설명: loop (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   loop : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       loop : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       loop := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: loop : UINT; // 초기값 없음!

✅ 안전: loop : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:5

설명: Step (BYTE): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Step : BYTE := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Step : BYTE := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Step := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Step : BYTE; // 초기값 없음!

✅ 안전: Step : BYTE := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:6

설명: bParameterSet (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bParameterSet : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bParameterSet : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bParameterSet := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bParameterSet : BOOL; // 초기값 없음!

✅ 안전: bParameterSet : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:7

설명: bModBusError (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bModBusError : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bModBusError : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bModBusError := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bModBusError : BOOL; // 초기값 없음!

✅ 안전: bModBusError : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:8

설명: bWriteRegs (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bWriteRegs : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bWriteRegs : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bWriteRegs := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bWriteRegs : BOOL; // 초기값 없음!

✅ 안전: bWriteRegs : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:16

설명: Err_Count (WORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Err_Count : WORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Err_Count : WORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Err_Count := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Err_Count : WORD; // 초기값 없음!

✅ 안전: Err_Count : WORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:18

설명: Err_TC_Comm_Count (WORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Err_TC_Comm_Count : WORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Err_TC_Comm_Count : WORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Err_TC_Comm_Count := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Err_TC_Comm_Count : WORD; // 초기값 없음!

✅ 안전: Err_TC_Comm_Count : WORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:19

설명: Err_CJC_Comm_Count (WORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Err_CJC_Comm_Count : WORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Err_CJC_Comm_Count : WORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Err_CJC_Comm_Count := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Err_CJC_Comm_Count : WORD; // 초기값 없음!

✅ 안전: Err_CJC_Comm_Count : WORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:20

설명: Err_Module_Comm_Count (WORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Err_Module_Comm_Count : WORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Err_Module_Comm_Count : WORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Err_Module_Comm_Count := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Err_Module_Comm_Count : WORD; // 초기값 없음!

✅ 안전: Err_Module_Comm_Count : WORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:21

설명: Err_Version_Comm_Count (WORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Err_Version_Comm_Count : WORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Err_Version_Comm_Count : WORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Err_Version_Comm_Count := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Err_Version_Comm_Count : WORD; // 초기값 없음!

✅ 안전: Err_Version_Comm_Count : WORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:32

설명: nModuleSts_Buff (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nModuleSts_Buff : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nModuleSts_Buff : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nModuleSts_Buff := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nModuleSts_Buff : UINT; // 초기값 없음!

✅ 안전: nModuleSts_Buff : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:76

설명: nLen (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nLen : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nLen : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nLen := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nLen : INT; // 초기값 없음!

✅ 안전: nLen : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:3

설명: bParamResult (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bParamResult : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bParamResult : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bParamResult := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bParamResult : BOOL; // 초기값 없음!

✅ 안전: bParamResult : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:20

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:107

설명: nTaskTime (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nTaskTime : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nTaskTime : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nTaskTime := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nTaskTime : UDINT; // 초기값 없음!

✅ 안전: nTaskTime : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:108

설명: nActTickCount_MV (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nActTickCount_MV : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nActTickCount_MV : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nActTickCount_MV := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nActTickCount_MV : UDINT; // 초기값 없음!

✅ 안전: nActTickCount_MV : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:109

설명: nActTickCount_SV (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nActTickCount_SV : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nActTickCount_SV : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nActTickCount_SV := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nActTickCount_SV : UDINT; // 초기값 없음!

✅ 안전: nActTickCount_SV : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:110

설명: nSetTickCount (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nSetTickCount : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nSetTickCount : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nSetTickCount := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nSetTickCount : UDINT; // 초기값 없음!

✅ 안전: nSetTickCount : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:145

설명: bFirstCheck (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bFirstCheck : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bFirstCheck : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bFirstCheck := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bFirstCheck : BOOL; // 초기값 없음!

✅ 안전: bFirstCheck : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:146

설명: bCompleteCheck (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bCompleteCheck : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bCompleteCheck : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bCompleteCheck := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bCompleteCheck : BOOL; // 초기값 없음!

✅ 안전: bCompleteCheck : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:147

설명: bMV_Scheduling (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bMV_Scheduling : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bMV_Scheduling : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bMV_Scheduling := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bMV_Scheduling : BOOL; // 초기값 없음!

✅ 안전: bMV_Scheduling : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:148

설명: bMV_Ramp (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bMV_Ramp : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bMV_Ramp : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bMV_Ramp := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bMV_Ramp : BOOL; // 초기값 없음!

✅ 안전: bMV_Ramp : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:152

설명: fWait_SchTime (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   fWait_SchTime : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       fWait_SchTime : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       fWait_SchTime := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: fWait_SchTime : UDINT; // 초기값 없음!

✅ 안전: fWait_SchTime : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:153

설명: nSch_TickCount (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nSch_TickCount : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nSch_TickCount : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nSch_TickCount := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nSch_TickCount : UDINT; // 초기값 없음!

✅ 안전: nSch_TickCount : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:154

설명: nSch_ElapsedTime (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nSch_ElapsedTime : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nSch_ElapsedTime : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nSch_ElapsedTime := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nSch_ElapsedTime : UDINT; // 초기값 없음!

✅ 안전: nSch_ElapsedTime : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:156

설명: bFirstCheckMV (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bFirstCheckMV : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bFirstCheckMV : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bFirstCheckMV := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bFirstCheckMV : BOOL; // 초기값 없음!

✅ 안전: bFirstCheckMV : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:157

설명: bFirstCheckSV (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   bFirstCheckSV : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       bFirstCheckSV : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       bFirstCheckSV := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: bFirstCheckSV : BOOL; // 초기값 없음!

✅ 안전: bFirstCheckSV : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:159

설명: Loop (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Loop : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Loop : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Loop := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Loop : UINT; // 초기값 없음!

✅ 안전: Loop : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:172

설명: ACC_One_Time_Check (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   ACC_One_Time_Check : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       ACC_One_Time_Check : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       ACC_One_Time_Check := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: ACC_One_Time_Check : BOOL; // 초기값 없음!

✅ 안전: ACC_One_Time_Check : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:174

설명: AutoTune_End_DelayTime_Trig (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AutoTune_End_DelayTime_Trig : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AutoTune_End_DelayTime_Trig : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AutoTune_End_DelayTime_Trig := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AutoTune_End_DelayTime_Trig : BOOL; // 초기값 없음!

✅ 안전: AutoTune_End_DelayTime_Trig : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:178

설명: AOC_Loop (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AOC_Loop : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AOC_Loop : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AOC_Loop := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AOC_Loop : INT; // 초기값 없음!

✅ 안전: AOC_Loop : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:195

설명: PowRatioSet (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   PowRatioSet : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       PowRatioSet : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       PowRatioSet := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: PowRatioSet : REAL; // 초기값 없음!

✅ 안전: PowRatioSet : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Function\F_TrendData_RealToString.TcPOU:11

설명: realData (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   realData : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       realData : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       realData := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: realData : REAL; // 초기값 없음!

✅ 안전: realData : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:5

설명: i (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   i : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       i : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       i := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: i : UINT; // 초기값 없음!

✅ 안전: i : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:23

설명: WriteFlag (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   WriteFlag : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       WriteFlag : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       WriteFlag := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: WriteFlag : BOOL; // 초기값 없음!

✅ 안전: WriteFlag : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:59

설명: curHour (WORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   curHour : WORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       curHour : WORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       curHour := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: curHour : WORD; // 초기값 없음!

✅ 안전: curHour : WORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:71

설명: nSize (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nSize : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nSize : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nSize := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nSize : UDINT; // 초기값 없음!

✅ 안전: nSize : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:16

설명: nSize (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nSize : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nSize : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nSize := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nSize : UDINT; // 초기값 없음!

✅ 안전: nSize : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:25

설명: addr_CopyMsg (POINTER): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   addr_CopyMsg : POINTER := NULL;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       addr_CopyMsg : POINTER := NULL;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       addr_CopyMsg := NULL;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: addr_CopyMsg : POINTER; // 초기값 없음!

✅ 안전: addr_CopyMsg : POINTER := NULL;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:61

설명: curDay (WORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   curDay : WORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       curDay : WORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       curDay := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: curDay : WORD; // 초기값 없음!

✅ 안전: curDay : WORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:64

설명: Log_Size (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Log_Size : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Log_Size : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Log_Size := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Log_Size : UINT; // 초기값 없음!

✅ 안전: Log_Size : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:65

설명: Log_Current_Step (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Log_Current_Step : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Log_Current_Step : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Log_Current_Step := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Log_Current_Step : UINT; // 초기값 없음!

✅ 안전: Log_Current_Step : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:15

설명: Alarm_States (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Alarm_States : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Alarm_States : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Alarm_States := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Alarm_States : BOOL; // 초기값 없음!

✅ 안전: Alarm_States : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:16

설명: Run_States (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Run_States : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Run_States : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Run_States := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Run_States : BOOL; // 초기값 없음!

✅ 안전: Run_States : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:17

설명: Idle_States (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   Idle_States : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       Idle_States : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       Idle_States := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: Idle_States : BOOL; // 초기값 없음!

✅ 안전: Idle_States : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:18

설명: PM_States (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   PM_States : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       PM_States : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       PM_States := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: PM_States : BOOL; // 초기값 없음!

✅ 안전: PM_States : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:19

설명: LP_States (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   LP_States : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       LP_States : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       LP_States := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: LP_States : BOOL; // 초기값 없음!

✅ 안전: LP_States : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:20

설명: LP2_States (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   LP2_States : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       LP2_States : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       LP2_States := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: LP2_States : BOOL; // 초기값 없음!

✅ 안전: LP2_States : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:22

설명: OldAlarm_States (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   OldAlarm_States : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       OldAlarm_States : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       OldAlarm_States := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: OldAlarm_States : BOOL; // 초기값 없음!

✅ 안전: OldAlarm_States : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:23

설명: OldRun_States (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   OldRun_States : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       OldRun_States : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       OldRun_States := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: OldRun_States : BOOL; // 초기값 없음!

✅ 안전: OldRun_States : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:24

설명: OldIdle_States (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   OldIdle_States : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       OldIdle_States : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       OldIdle_States := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: OldIdle_States : BOOL; // 초기값 없음!

✅ 안전: OldIdle_States : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:25

설명: OldPM_States (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   OldPM_States : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       OldPM_States : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       OldPM_States := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: OldPM_States : BOOL; // 초기값 없음!

✅ 안전: OldPM_States : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:26

설명: OldLP_States (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   OldLP_States : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       OldLP_States : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       OldLP_States := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: OldLP_States : BOOL; // 초기값 없음!

✅ 안전: OldLP_States : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:28

설명: OldAlarm_Color (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   OldAlarm_Color : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       OldAlarm_Color : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       OldAlarm_Color := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: OldAlarm_Color : UINT; // 초기값 없음!

✅ 안전: OldAlarm_Color : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:29

설명: OldRun_Color (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   OldRun_Color : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       OldRun_Color : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       OldRun_Color := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: OldRun_Color : UINT; // 초기값 없음!

✅ 안전: OldRun_Color : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:30

설명: OldIdle_Color (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   OldIdle_Color : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       OldIdle_Color : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       OldIdle_Color := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: OldIdle_Color : UINT; // 초기값 없음!

✅ 안전: OldIdle_Color : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:31

설명: OldPM_Color (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   OldPM_Color : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       OldPM_Color : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       OldPM_Color := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: OldPM_Color : UINT; // 초기값 없음!

✅ 안전: OldPM_Color : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:32

설명: OldLP_Color (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   OldLP_Color : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       OldLP_Color : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       OldLP_Color := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: OldLP_Color : UINT; // 초기값 없음!

✅ 안전: OldLP_Color : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivByte.TcPOU:2

설명: divisor (BYTE): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   divisor : BYTE := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       divisor : BYTE := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       divisor := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: divisor : BYTE; // 초기값 없음!

✅ 안전: divisor : BYTE := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivDint.TcPOU:2

설명: divisor (DINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   divisor : DINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       divisor : DINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       divisor := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: divisor : DINT; // 초기값 없음!

✅ 안전: divisor : DINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivDWord.TcPOU:2

설명: divisor (DWORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   divisor : DWORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       divisor : DWORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       divisor := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: divisor : DWORD; // 초기값 없음!

✅ 안전: divisor : DWORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivInt.TcPOU:2

설명: divisor (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   divisor : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       divisor : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       divisor := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: divisor : INT; // 초기값 없음!

✅ 안전: divisor : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivLreal.TcPOU:2

설명: divisor (LREAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   divisor : LREAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       divisor : LREAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       divisor := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: divisor : LREAL; // 초기값 없음!

✅ 안전: divisor : LREAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivReal.TcPOU:2

설명: divisor (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   divisor : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       divisor : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       divisor := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: divisor : REAL; // 초기값 없음!

✅ 안전: divisor : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivWord.TcPOU:2

설명: divisor (WORD): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   divisor : WORD := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       divisor : WORD := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       divisor := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: divisor : WORD; // 초기값 없음!

✅ 안전: divisor : WORD := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Globale_VarCheck.TcGVL:3

설명: CheckBounds_ErrCnt (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   CheckBounds_ErrCnt : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       CheckBounds_ErrCnt : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       CheckBounds_ErrCnt := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: CheckBounds_ErrCnt : INT; // 초기값 없음!

✅ 안전: CheckBounds_ErrCnt : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Globale_VarCheck.TcGVL:4

설명: CheckByteZeroDiv_ErrCnt (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   CheckByteZeroDiv_ErrCnt : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       CheckByteZeroDiv_ErrCnt : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       CheckByteZeroDiv_ErrCnt := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: CheckByteZeroDiv_ErrCnt : INT; // 초기값 없음!

✅ 안전: CheckByteZeroDiv_ErrCnt : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Globale_VarCheck.TcGVL:5

설명: CheckDintZeroDiv_ErrCnt (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   CheckDintZeroDiv_ErrCnt : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       CheckDintZeroDiv_ErrCnt : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       CheckDintZeroDiv_ErrCnt := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: CheckDintZeroDiv_ErrCnt : INT; // 초기값 없음!

✅ 안전: CheckDintZeroDiv_ErrCnt : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Globale_VarCheck.TcGVL:6

설명: CheckDWordZeroDiv_ErrCnt (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   CheckDWordZeroDiv_ErrCnt : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       CheckDWordZeroDiv_ErrCnt : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       CheckDWordZeroDiv_ErrCnt := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: CheckDWordZeroDiv_ErrCnt : INT; // 초기값 없음!

✅ 안전: CheckDWordZeroDiv_ErrCnt : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Globale_VarCheck.TcGVL:7

설명: CheckIntZeroDiv_ErrCnt (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   CheckIntZeroDiv_ErrCnt : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       CheckIntZeroDiv_ErrCnt : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       CheckIntZeroDiv_ErrCnt := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: CheckIntZeroDiv_ErrCnt : INT; // 초기값 없음!

✅ 안전: CheckIntZeroDiv_ErrCnt : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Globale_VarCheck.TcGVL:8

설명: CheckLrealZeroDiv_ErrCnt (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   CheckLrealZeroDiv_ErrCnt : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       CheckLrealZeroDiv_ErrCnt : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       CheckLrealZeroDiv_ErrCnt := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: CheckLrealZeroDiv_ErrCnt : INT; // 초기값 없음!

✅ 안전: CheckLrealZeroDiv_ErrCnt : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Globale_VarCheck.TcGVL:9

설명: CheckRealZeroDiv_ErrCnt (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   CheckRealZeroDiv_ErrCnt : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       CheckRealZeroDiv_ErrCnt : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       CheckRealZeroDiv_ErrCnt := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: CheckRealZeroDiv_ErrCnt : INT; // 초기값 없음!

✅ 안전: CheckRealZeroDiv_ErrCnt : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Globale_VarCheck.TcGVL:10

설명: CheckSIntZeroDiv_ErrCnt (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   CheckSIntZeroDiv_ErrCnt : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       CheckSIntZeroDiv_ErrCnt : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       CheckSIntZeroDiv_ErrCnt := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: CheckSIntZeroDiv_ErrCnt : INT; // 초기값 없음!

✅ 안전: CheckSIntZeroDiv_ErrCnt : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Globale_VarCheck.TcGVL:11

설명: CheckWordZeroDiv_ErrCnt (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   CheckWordZeroDiv_ErrCnt : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       CheckWordZeroDiv_ErrCnt : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       CheckWordZeroDiv_ErrCnt := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: CheckWordZeroDiv_ErrCnt : INT; // 초기값 없음!

✅ 안전: CheckWordZeroDiv_ErrCnt : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Globale_VarCheck.TcGVL:12

설명: CheckRangeSigned_ErrCnt (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   CheckRangeSigned_ErrCnt : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       CheckRangeSigned_ErrCnt : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       CheckRangeSigned_ErrCnt := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: CheckRangeSigned_ErrCnt : INT; // 초기값 없음!

✅ 안전: CheckRangeSigned_ErrCnt : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Globale_VarCheck.TcGVL:13

설명: CheckRangeUnsigned (INT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   CheckRangeUnsigned : INT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       CheckRangeUnsigned : INT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       CheckRangeUnsigned := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: CheckRangeUnsigned : INT; // 초기값 없음!

✅ 안전: CheckRangeUnsigned : INT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables.TcGVL:7

설명: gState_CapClose (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   gState_CapClose : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       gState_CapClose : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       gState_CapClose := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: gState_CapClose : BOOL; // 초기값 없음!

✅ 안전: gState_CapClose : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables.TcGVL:8

설명: gState_GasLeak (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   gState_GasLeak : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       gState_GasLeak : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       gState_GasLeak := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: gState_GasLeak : BOOL; // 초기값 없음!

✅ 안전: gState_GasLeak : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables.TcGVL:9

설명: gState_MS (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   gState_MS : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       gState_MS : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       gState_MS := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: gState_MS : BOOL; // 초기값 없음!

✅ 안전: gState_MS : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:2967

설명: DX_Heater_Profile_Tune_End_Condition (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DX_Heater_Profile_Tune_End_Condition : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DX_Heater_Profile_Tune_End_Condition : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DX_Heater_Profile_Tune_End_Condition := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DX_Heater_Profile_Tune_End_Condition : BOOL; // 초기값 없음!

✅ 안전: DX_Heater_Profile_Tune_End_Condition : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3813

설명: nCycleTime (UDINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   nCycleTime : UDINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       nCycleTime : UDINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       nCycleTime := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: nCycleTime : UDINT; // 초기값 없음!

✅ 안전: nCycleTime : UDINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3818

설명: DI_Heater_Power_Module (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DI_Heater_Power_Module : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DI_Heater_Power_Module : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DI_Heater_Power_Module := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DI_Heater_Power_Module : BOOL; // 초기값 없음!

✅ 안전: DI_Heater_Power_Module : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3819

설명: DI_Heater_AI01_Module (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DI_Heater_AI01_Module : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DI_Heater_AI01_Module : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DI_Heater_AI01_Module := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DI_Heater_AI01_Module : BOOL; // 초기값 없음!

✅ 안전: DI_Heater_AI01_Module : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3820

설명: DI_Heater_AI02_Module (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DI_Heater_AI02_Module : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DI_Heater_AI02_Module : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DI_Heater_AI02_Module := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DI_Heater_AI02_Module : BOOL; // 초기값 없음!

✅ 안전: DI_Heater_AI02_Module : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3821

설명: DI_Heater_AI03_Module (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DI_Heater_AI03_Module : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DI_Heater_AI03_Module : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DI_Heater_AI03_Module := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DI_Heater_AI03_Module : BOOL; // 초기값 없음!

✅ 안전: DI_Heater_AI03_Module : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3822

설명: DI_Heater_AI04_Module (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DI_Heater_AI04_Module : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DI_Heater_AI04_Module : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DI_Heater_AI04_Module := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DI_Heater_AI04_Module : BOOL; // 초기값 없음!

✅ 안전: DI_Heater_AI04_Module : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3823

설명: DI_Heater_AI05_Module (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DI_Heater_AI05_Module : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DI_Heater_AI05_Module : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DI_Heater_AI05_Module := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DI_Heater_AI05_Module : BOOL; // 초기값 없음!

✅ 안전: DI_Heater_AI05_Module : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3824

설명: DI_Heater_AI06_Module (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DI_Heater_AI06_Module : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DI_Heater_AI06_Module : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DI_Heater_AI06_Module := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DI_Heater_AI06_Module : BOOL; // 초기값 없음!

✅ 안전: DI_Heater_AI06_Module : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3825

설명: DI_Heater_AI07_Module (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DI_Heater_AI07_Module : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DI_Heater_AI07_Module : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DI_Heater_AI07_Module := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DI_Heater_AI07_Module : BOOL; // 초기값 없음!

✅ 안전: DI_Heater_AI07_Module : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3826

설명: DI_Heater_AO01_Module (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DI_Heater_AO01_Module : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DI_Heater_AO01_Module : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DI_Heater_AO01_Module := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DI_Heater_AO01_Module : BOOL; // 초기값 없음!

✅ 안전: DI_Heater_AO01_Module : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3827

설명: DI_Heater_AO02_Module (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DI_Heater_AO02_Module : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DI_Heater_AO02_Module : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DI_Heater_AO02_Module := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DI_Heater_AO02_Module : BOOL; // 초기값 없음!

✅ 안전: DI_Heater_AO02_Module : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3837

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 20개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 20개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3838

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 21개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 21개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3841

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 22개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 22개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3842

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 23개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 23개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3843

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 24개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 24개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3844

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 25개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 25개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3845

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 26개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 26개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3847

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 27개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 27개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3848

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 28개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 28개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3849

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 29개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 29개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3850

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 30개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 30개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3851

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 31개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 31개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3852

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 32개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 32개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3854

설명: DO_Heater_PID_AT_Run (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DO_Heater_PID_AT_Run : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DO_Heater_PID_AT_Run : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DO_Heater_PID_AT_Run := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DO_Heater_PID_AT_Run : BOOL; // 초기값 없음!

✅ 안전: DO_Heater_PID_AT_Run : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3854

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 33개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 33개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3855

설명: DO_Heater_Power_OnOff (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DO_Heater_Power_OnOff : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DO_Heater_Power_OnOff : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DO_Heater_Power_OnOff := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DO_Heater_Power_OnOff : BOOL; // 초기값 없음!

✅ 안전: DO_Heater_Power_OnOff : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3855

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 34개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 34개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3859

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 35개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 35개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3860

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 36개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 36개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3861

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 37개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 37개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3862

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 38개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 38개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3863

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 39개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 39개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3864

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 40개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 40개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3868

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 41개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 41개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3869

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 42개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 42개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3870

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 43개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 43개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3872

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 44개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 44개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3873

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 45개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 45개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3874

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 46개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 46개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3875

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 47개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 47개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3877

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 48개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 48개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3879

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 49개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 49개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3880

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 50개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 50개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3881

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 51개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 51개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3883

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 52개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 52개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3885

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 53개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 53개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3886

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 54개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 54개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3887

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 55개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 55개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3888

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 56개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 56개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3889

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 57개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 57개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3890

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 58개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 58개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3891

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 59개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 59개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3892

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 60개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 60개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3893

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 61개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 61개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3894

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 62개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 62개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3895

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 63개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 63개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3896

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 64개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 64개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3897

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 65개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 65개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3898

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 66개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 66개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3899

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 67개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 67개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3900

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 68개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 68개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3901

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 69개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 69개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3902

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 70개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 70개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3903

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 71개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 71개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3905

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 72개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 72개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3906

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 73개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 73개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3907

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 74개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 74개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3908

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 75개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 75개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3909

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 76개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 76개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3911

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 77개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 77개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3913

설명: DX_INF_Dcoll_Log (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DX_INF_Dcoll_Log : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DX_INF_Dcoll_Log : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DX_INF_Dcoll_Log := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DX_INF_Dcoll_Log : BOOL; // 초기값 없음!

✅ 안전: DX_INF_Dcoll_Log : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3913

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 78개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 78개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3914

설명: DX_INF_Para_Log (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DX_INF_Para_Log : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DX_INF_Para_Log : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DX_INF_Para_Log := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DX_INF_Para_Log : BOOL; // 초기값 없음!

✅ 안전: DX_INF_Para_Log : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3914

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 79개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 79개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3916

설명: DX_INF_FRP_End_Condition (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DX_INF_FRP_End_Condition : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DX_INF_FRP_End_Condition : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DX_INF_FRP_End_Condition := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DX_INF_FRP_End_Condition : BOOL; // 초기값 없음!

✅ 안전: DX_INF_FRP_End_Condition : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3916

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 80개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 80개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3919

설명: AI_Dnet_MFC01_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC01_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC01_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC01_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC01_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC01_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3919

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 81개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 81개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3920

설명: AI_Dnet_MFC02_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC02_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC02_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC02_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC02_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC02_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3920

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 82개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 82개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3921

설명: AI_Dnet_MFC03_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC03_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC03_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC03_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC03_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC03_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3921

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 83개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 83개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3922

설명: AI_Dnet_MFC04_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC04_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC04_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC04_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC04_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC04_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3922

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 84개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 84개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3924

설명: AI_Dnet_MFC05_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC05_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC05_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC05_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC05_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC05_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3924

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 85개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 85개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3925

설명: AI_Dnet_MFC06_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC06_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC06_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC06_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC06_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC06_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3925

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 86개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 86개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3926

설명: AI_Dnet_MFC07_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC07_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC07_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC07_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC07_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC07_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3926

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 87개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 87개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3927

설명: AI_Dnet_MFC08_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC08_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC08_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC08_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC08_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC08_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3927

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 88개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 88개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3929

설명: AI_Dnet_MFC09_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC09_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC09_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC09_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC09_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC09_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3929

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 89개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 89개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3930

설명: AI_Dnet_MFC10_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC10_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC10_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC10_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC10_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC10_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3930

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 90개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 90개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3931

설명: AI_Dnet_MFC11_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC11_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC11_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC11_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC11_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC11_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3931

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 91개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 91개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3932

설명: AI_Dnet_MFC12_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC12_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC12_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC12_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC12_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC12_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3932

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 92개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 92개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3934

설명: AI_Dnet_MFC13_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC13_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC13_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC13_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC13_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC13_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3934

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 93개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 93개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3935

설명: AI_Dnet_MFC14_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC14_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC14_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC14_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC14_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC14_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3935

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 94개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 94개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3936

설명: AI_Dnet_MFC15_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC15_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC15_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC15_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC15_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC15_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3936

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 95개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 95개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3938

설명: AI_Dnet_MFC16_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC16_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC16_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC16_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC16_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC16_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3938

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 96개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 96개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3939

설명: AI_Dnet_MFC17_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC17_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC17_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC17_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC17_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC17_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3939

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 97개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 97개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3940

설명: AI_Dnet_MFC18_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC18_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC18_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC18_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC18_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC18_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3940

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 98개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 98개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3941

설명: AI_Dnet_MFC19_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC19_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC19_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC19_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC19_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC19_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3941

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 99개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 99개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3943

설명: AI_Dnet_MFC20_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC20_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC20_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC20_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC20_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC20_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3943

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 100개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 100개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3944

설명: AI_Dnet_MFC21_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC21_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC21_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC21_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC21_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC21_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3944

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 101개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 101개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3945

설명: AI_Dnet_MFC22_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC22_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC22_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC22_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC22_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC22_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3945

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 102개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 102개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3946

설명: AI_Dnet_MFC23_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC23_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC23_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC23_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC23_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC23_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3946

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 103개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 103개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3948

설명: AI_Dnet_MFC24_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC24_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC24_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC24_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC24_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC24_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3948

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 104개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 104개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3949

설명: AI_Dnet_MFC25_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC25_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC25_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC25_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC25_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC25_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3949

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 105개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 105개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3951

설명: AI_Dnet_MFC41_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC41_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC41_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC41_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC41_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC41_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3951

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 106개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 106개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3952

설명: AI_Dnet_MFC42_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC42_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC42_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC42_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC42_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC42_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3952

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 107개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 107개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3953

설명: AI_Dnet_MFC43_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC43_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC43_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC43_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC43_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC43_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3953

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 108개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 108개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3954

설명: AI_Dnet_MFC44_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC44_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC44_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC44_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC44_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC44_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3954

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 109개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 109개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3955

설명: AI_Dnet_MFC45_RAMPING_TIME (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC45_RAMPING_TIME : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC45_RAMPING_TIME : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC45_RAMPING_TIME := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC45_RAMPING_TIME : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC45_RAMPING_TIME : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3955

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 110개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 110개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3957

설명: AI_Dnet_MFC01_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC01_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC01_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC01_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC01_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC01_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3957

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 111개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 111개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3958

설명: AI_Dnet_MFC02_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC02_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC02_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC02_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC02_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC02_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3958

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 112개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 112개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3959

설명: AI_Dnet_MFC03_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC03_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC03_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC03_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC03_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC03_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3959

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 113개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 113개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3960

설명: AI_Dnet_MFC04_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC04_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC04_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC04_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC04_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC04_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3960

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 114개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 114개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3962

설명: AI_Dnet_MFC05_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC05_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC05_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC05_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC05_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC05_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3962

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 115개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 115개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3963

설명: AI_Dnet_MFC06_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC06_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC06_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC06_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC06_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC06_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3963

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 116개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 116개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3964

설명: AI_Dnet_MFC07_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC07_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC07_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC07_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC07_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC07_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3964

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 117개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 117개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3965

설명: AI_Dnet_MFC08_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC08_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC08_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC08_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC08_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC08_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3965

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 118개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 118개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3967

설명: AI_Dnet_MFC09_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC09_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC09_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC09_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC09_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC09_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3967

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 119개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 119개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3968

설명: AI_Dnet_MFC10_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC10_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC10_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC10_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC10_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC10_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3968

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 120개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 120개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3969

설명: AI_Dnet_MFC11_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC11_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC11_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC11_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC11_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC11_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3969

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 121개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 121개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3970

설명: AI_Dnet_MFC12_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC12_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC12_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC12_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC12_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC12_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3970

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 122개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 122개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3972

설명: AI_Dnet_MFC13_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC13_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC13_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC13_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC13_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC13_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3972

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 123개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 123개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3973

설명: AI_Dnet_MFC14_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC14_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC14_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC14_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC14_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC14_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3973

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 124개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 124개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3974

설명: AI_Dnet_MFC15_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC15_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC15_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC15_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC15_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC15_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3974

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 125개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 125개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3975

설명: AI_Dnet_MFC16_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC16_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC16_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC16_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC16_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC16_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3975

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 126개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 126개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3977

설명: AI_Dnet_MFC17_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC17_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC17_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC17_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC17_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC17_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3977

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 127개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 127개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3978

설명: AI_Dnet_MFC18_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC18_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC18_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC18_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC18_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC18_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3978

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 128개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 128개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3979

설명: AI_Dnet_MFC19_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC19_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC19_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC19_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC19_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC19_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3979

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 129개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 129개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3980

설명: AI_Dnet_MFC20_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC20_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC20_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC20_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC20_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC20_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3980

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 130개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 130개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3982

설명: AI_Dnet_MFC21_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC21_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC21_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC21_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC21_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC21_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3982

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 131개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 131개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3983

설명: AI_Dnet_MFC22_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC22_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC22_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC22_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC22_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC22_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3983

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 132개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 132개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3984

설명: AI_Dnet_MFC23_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC23_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC23_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC23_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC23_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC23_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3984

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 133개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 133개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3985

설명: AI_Dnet_MFC24_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC24_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC24_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC24_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC24_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC24_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3985

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 134개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 134개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3987

설명: AI_Dnet_MFC25_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC25_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC25_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC25_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC25_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC25_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3987

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 135개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 135개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3989

설명: AI_Dnet_MFC41_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC41_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC41_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC41_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC41_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC41_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3989

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 136개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 136개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3990

설명: AI_Dnet_MFC42_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC42_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC42_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC42_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC42_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC42_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3990

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 137개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 137개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3991

설명: AI_Dnet_MFC43_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC43_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC43_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC43_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC43_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC43_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3991

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 138개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 138개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3992

설명: AI_Dnet_MFC44_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC44_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC44_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC44_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC44_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC44_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3992

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 139개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 139개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3993

설명: AI_Dnet_MFC45_FULL_SCALE (UINT): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_Dnet_MFC45_FULL_SCALE : UINT := 0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_Dnet_MFC45_FULL_SCALE : UINT := 0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_Dnet_MFC45_FULL_SCALE := 0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_Dnet_MFC45_FULL_SCALE : UINT; // 초기값 없음!

✅ 안전: AI_Dnet_MFC45_FULL_SCALE : UINT := 0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3993

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 140개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 140개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3995

설명: DI_LH_Power (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DI_LH_Power : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DI_LH_Power : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DI_LH_Power := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DI_LH_Power : BOOL; // 초기값 없음!

✅ 안전: DI_LH_Power : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3995

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 141개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 141개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3997

설명: DI_Pump_Power (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DI_Pump_Power : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DI_Pump_Power : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DI_Pump_Power := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DI_Pump_Power : BOOL; // 초기값 없음!

✅ 안전: DI_Pump_Power : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3997

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 142개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 142개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3999

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 143개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 143개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4001

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 144개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 144개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4003

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 145개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 145개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4005

설명: STS_EMG_Trig (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   STS_EMG_Trig : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       STS_EMG_Trig : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       STS_EMG_Trig := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: STS_EMG_Trig : BOOL; // 초기값 없음!

✅ 안전: STS_EMG_Trig : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4005

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 146개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 146개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4006

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 147개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 147개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4007

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 148개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 148개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4009

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 149개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 149개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4010

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 150개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 150개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4011

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 151개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 151개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4013

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 152개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 152개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4015

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 153개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 153개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4016

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 154개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 154개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4017

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 155개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 155개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4019

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 156개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 156개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4020

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 157개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 157개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4022

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 158개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 158개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4023

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 159개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 159개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4025

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 160개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 160개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4026

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 161개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 161개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4028

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 162개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 162개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4029

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 163개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 163개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4030

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 164개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 164개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4032

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 165개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 165개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4033

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 166개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 166개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4035

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 167개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 167개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4036

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 168개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 168개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4038

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 169개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 169개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4039

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 170개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 170개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4040

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 171개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 171개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4042

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 172개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 172개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4043

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 173개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 173개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4045

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 174개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 174개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4046

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 175개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 175개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4048

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 176개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 176개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4049

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 177개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 177개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4051

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 178개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 178개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4052

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 179개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 179개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4054

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 180개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 180개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4055

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 181개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 181개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4057

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 182개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 182개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4058

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 183개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 183개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4060

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 184개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 184개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4061

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 185개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 185개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4063

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 186개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 186개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4064

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 187개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 187개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4066

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 188개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 188개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4067

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 189개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 189개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4069

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 190개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 190개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4070

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 191개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 191개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4072

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 192개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 192개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4073

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 193개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 193개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4075

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 194개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 194개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4076

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 195개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 195개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4078

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 196개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 196개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4079

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 197개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 197개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4081

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 198개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 198개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4082

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 199개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 199개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4084

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 200개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 200개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4085

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 201개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 201개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4087

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 202개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 202개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4088

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 203개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 203개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4090

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 204개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 204개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4091

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 205개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 205개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4098

설명: AX_PHY_Boat_Single_Speed (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AX_PHY_Boat_Single_Speed : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AX_PHY_Boat_Single_Speed : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AX_PHY_Boat_Single_Speed := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AX_PHY_Boat_Single_Speed : REAL; // 초기값 없음!

✅ 안전: AX_PHY_Boat_Single_Speed : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4098

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 206개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 206개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4100

설명: AX_PHY_Boat_Multi_Speed1 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AX_PHY_Boat_Multi_Speed1 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AX_PHY_Boat_Multi_Speed1 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AX_PHY_Boat_Multi_Speed1 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AX_PHY_Boat_Multi_Speed1 : REAL; // 초기값 없음!

✅ 안전: AX_PHY_Boat_Multi_Speed1 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4100

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 207개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 207개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4101

설명: AX_PHY_Boat_Multi_Speed2 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AX_PHY_Boat_Multi_Speed2 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AX_PHY_Boat_Multi_Speed2 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AX_PHY_Boat_Multi_Speed2 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AX_PHY_Boat_Multi_Speed2 : REAL; // 초기값 없음!

✅ 안전: AX_PHY_Boat_Multi_Speed2 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4101

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 208개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 208개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4102

설명: AX_PHY_Boat_Multi_Speed3 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AX_PHY_Boat_Multi_Speed3 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AX_PHY_Boat_Multi_Speed3 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AX_PHY_Boat_Multi_Speed3 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AX_PHY_Boat_Multi_Speed3 : REAL; // 초기값 없음!

✅ 안전: AX_PHY_Boat_Multi_Speed3 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4102

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 209개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 209개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4103

설명: AX_PHY_Boat_Multi_Speed4 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AX_PHY_Boat_Multi_Speed4 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AX_PHY_Boat_Multi_Speed4 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AX_PHY_Boat_Multi_Speed4 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AX_PHY_Boat_Multi_Speed4 : REAL; // 초기값 없음!

✅ 안전: AX_PHY_Boat_Multi_Speed4 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4103

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 210개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 210개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4104

설명: AX_PHY_Boat_Multi_Speed5 (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AX_PHY_Boat_Multi_Speed5 : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AX_PHY_Boat_Multi_Speed5 : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AX_PHY_Boat_Multi_Speed5 := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AX_PHY_Boat_Multi_Speed5 : REAL; // 초기값 없음!

✅ 안전: AX_PHY_Boat_Multi_Speed5 : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4104

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 211개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 211개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4105

설명: AX_PHY_Boat_Up_Speed (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AX_PHY_Boat_Up_Speed : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AX_PHY_Boat_Up_Speed : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AX_PHY_Boat_Up_Speed := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AX_PHY_Boat_Up_Speed : REAL; // 초기값 없음!

✅ 안전: AX_PHY_Boat_Up_Speed : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4105

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 212개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 212개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4107

설명: AX_INF_Current_AbortAlarm (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AX_INF_Current_AbortAlarm : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AX_INF_Current_AbortAlarm : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AX_INF_Current_AbortAlarm := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AX_INF_Current_AbortAlarm : REAL; // 초기값 없음!

✅ 안전: AX_INF_Current_AbortAlarm : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4107

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 213개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 213개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4109

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 214개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 214개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4111

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 215개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 215개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4112

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 216개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 216개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4113

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 217개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 217개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4114

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 218개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 218개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4115

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 219개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 219개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4117

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 220개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 220개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4118

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 221개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 221개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4120

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 222개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 222개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4121

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 223개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 223개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4122

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 224개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 224개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4123

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 225개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 225개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4124

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 226개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 226개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4127

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 227개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 227개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4129

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 228개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 228개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4131

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 229개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 229개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4133

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 230개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 230개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4135

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 231개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 231개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4138

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 232개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 232개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4140

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 233개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 233개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4141

설명: DX_FF_Reset (BOOL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   DX_FF_Reset : BOOL := FALSE;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       DX_FF_Reset : BOOL := FALSE;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       DX_FF_Reset := FALSE;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: DX_FF_Reset : BOOL; // 초기값 없음!

✅ 안전: DX_FF_Reset : BOOL := FALSE;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4141

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 234개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 234개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4142

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 235개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 235개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4144

설명: AI_VG_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AI_VG_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AI_VG_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AI_VG_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AI_VG_Pressure : REAL; // 초기값 없음!

✅ 안전: AI_VG_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4144

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 236개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 236개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4146

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 237개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 237개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4148

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 238개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 238개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Persistent.TcGVL:673

설명: AX_Loadlock_GAS01_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AX_Loadlock_GAS01_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AX_Loadlock_GAS01_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AX_Loadlock_GAS01_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AX_Loadlock_GAS01_Set : REAL; // 초기값 없음!

✅ 안전: AX_Loadlock_GAS01_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Persistent.TcGVL:674

설명: AX_Loadlock_GAS02_Set (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AX_Loadlock_GAS02_Set : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AX_Loadlock_GAS02_Set : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AX_Loadlock_GAS02_Set := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AX_Loadlock_GAS02_Set : REAL; // 초기값 없음!

✅ 안전: AX_Loadlock_GAS02_Set : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Persistent.TcGVL:676

설명: AX_Loadlock_GAS01_Ramping (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AX_Loadlock_GAS01_Ramping : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AX_Loadlock_GAS01_Ramping : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AX_Loadlock_GAS01_Ramping := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AX_Loadlock_GAS01_Ramping : REAL; // 초기값 없음!

✅ 안전: AX_Loadlock_GAS01_Ramping : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Persistent.TcGVL:677

설명: AX_Loadlock_GAS02_Ramping (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AX_Loadlock_GAS02_Ramping : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AX_Loadlock_GAS02_Ramping : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AX_Loadlock_GAS02_Ramping := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AX_Loadlock_GAS02_Ramping : REAL; // 초기값 없음!

✅ 안전: AX_Loadlock_GAS02_Ramping : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Persistent.TcGVL:680

설명: AX_Loadlock_RSD_TOP_Position (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AX_Loadlock_RSD_TOP_Position : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AX_Loadlock_RSD_TOP_Position : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AX_Loadlock_RSD_TOP_Position := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AX_Loadlock_RSD_TOP_Position : REAL; // 초기값 없음!

✅ 안전: AX_Loadlock_RSD_TOP_Position : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA002] 변수가 초기화되지 않음

카테고리: 초기화 누락

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Persistent.TcGVL:681

설명: AX_Loadlock_RSD_TOP_Pressure (REAL): 초기값 없이 선언되어 예측 불가능한 값을 가질 수 있음

⚠️ 위험성:

초기화되지 않은 변수는 메모리에 남아있던 임의의 값을 가집니다. PLC 재시작 시마다 다른 값을 가질 수 있어 예측 불가능한 동작을 유발합니다. 특히 BOOL 타입의 경우 안전 로직에서 치명적인 오류를 발생시킬 수 있습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 초기화 (가장 권장)
   AX_Loadlock_RSD_TOP_Pressure : REAL := 0.0;

2. VAR_STAT 사용 시 RETAIN으로 값 유지
   VAR_STAT
       AX_Loadlock_RSD_TOP_Pressure : REAL := 0.0;
   END_VAR

3. 초기화 로직 추가
   IF NOT initialized THEN
       AX_Loadlock_RSD_TOP_Pressure := 0.0;
       initialized := TRUE;
   END_IF

예시:

❌ 위험: AX_Loadlock_RSD_TOP_Pressure : REAL; // 초기값 없음!

✅ 안전: AX_Loadlock_RSD_TOP_Pressure : REAL := 0.0;

// 특히 BOOL 타입은 반드시 초기화
isEnabled : BOOL := FALSE;
emergencyStop : BOOL := FALSE;
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\MAIN.TcPOU:1

설명: MAIN: 1240줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: MAIN = 1240줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\MAIN.TcPOU:1

설명: Boot = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Boot - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Boot >= (FALSE - 1.0E-6) AND
      Boot <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Boot >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Boot * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Boot = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Boot - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\MAIN.TcPOU:1

설명: Simulation = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Simulation - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Simulation >= (TRUE - 1.0E-6) AND
      Simulation <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Simulation >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Simulation * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Simulation = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Simulation - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\MAIN.TcPOU:1

설명: bGet_NetID = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(bGet_NetID - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF bGet_NetID >= (FALSE - 1.0E-6) AND
      bGet_NetID <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF bGet_NetID >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(bGet_NetID * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF bGet_NetID = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(bGet_NetID - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\MAIN.TcPOU:1

설명: DX_INF_IOCheckMode = eUsable_Yes: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_IOCheckMode - eUsable_Yes) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_IOCheckMode >= (eUsable_Yes - 1.0E-6) AND
      DX_INF_IOCheckMode <= (eUsable_Yes + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_IOCheckMode >= eUsable_Yes THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_IOCheckMode * 10.0);
   intTarget := REAL_TO_DINT(eUsable_Yes * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_IOCheckMode = eUsable_Yes THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_IOCheckMode - eUsable_Yes) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\MAIN.TcPOU:1

설명: DX_INF_State_Module = eModule_Offline: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Offline) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Offline - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Offline + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Offline THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Offline * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Offline THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Offline) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\MAIN.TcPOU:1

설명: DX_INF_IOCheckMode = eUsable_Yes: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_IOCheckMode - eUsable_Yes) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_IOCheckMode >= (eUsable_Yes - 1.0E-6) AND
      DX_INF_IOCheckMode <= (eUsable_Yes + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_IOCheckMode >= eUsable_Yes THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_IOCheckMode * 10.0);
   intTarget := REAL_TO_DINT(eUsable_Yes * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_IOCheckMode = eUsable_Yes THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_IOCheckMode - eUsable_Yes) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\MAIN.TcPOU:1

설명: Simulation = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Simulation - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Simulation >= (TRUE - 1.0E-6) AND
      Simulation <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Simulation >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Simulation * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Simulation = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Simulation - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\MAIN_10ms.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\MAIN_10ms.TcPOU:1

설명: Boot = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Boot - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Boot >= (FALSE - 1.0E-6) AND
      Boot <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Boot >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Boot * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Boot = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Boot - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\MAIN_10ms.TcPOU:1

설명: Boot = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Boot - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Boot >= (FALSE - 1.0E-6) AND
      Boot <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Boot >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Boot * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Boot = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Boot - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\MAIN_10ms.TcPOU:1

설명: fbAlarm[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := fbAlarm[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := fbAlarm[Loop];
   END_IF

예시:

❌ 위험: value := fbAlarm[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := fbAlarm[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\MAIN_10ms.TcPOU:1

설명: fbAlarm[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := fbAlarm[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := fbAlarm[Loop];
   END_IF

예시:

❌ 위험: value := fbAlarm[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := fbAlarm[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\MAIN_10ms.TcPOU:1

설명: pALM[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := pALM[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := pALM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := pALM[Loop];
   END_IF

예시:

❌ 위험: value := pALM[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := pALM[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: RangeNo = 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(RangeNo - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF RangeNo >= (0 - 1.0E-6) AND
      RangeNo <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF RangeNo >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(RangeNo * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF RangeNo = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(RangeNo - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: RangeNo = 6: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(RangeNo - 6) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF RangeNo >= (6 - 1.0E-6) AND
      RangeNo <= (6 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF RangeNo >= 6 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(RangeNo * 10.0);
   intTarget := REAL_TO_DINT(6 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF RangeNo = 6 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(RangeNo - 6) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: Range_1_Value <> 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Range_1_Value - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Range_1_Value >= (0 - 1.0E-6) AND
      Range_1_Value <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Range_1_Value >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Range_1_Value * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Range_1_Value = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Range_1_Value - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Range]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Range >= 1 AND
      1..cMAX_Heater_Range <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Range];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Range, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Range >= ARRAY_MIN AND 1..cMAX_Heater_Range <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Range];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Range]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Range >= 1 AND 1..cMAX_Heater_Range <= 10 THEN
value := ARRAY[1..cMAX_Heater_Range];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: TempSV[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := TempSV[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := TempSV[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := TempSV[i];
   END_IF

예시:

❌ 위험: value := TempSV[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := TempSV[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ParamTable[1, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1, i >= 1 AND
      1, i <= 10 THEN
       value := ParamTable[1, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1, i >= ARRAY_MIN AND 1, i <= ARRAY_MAX THEN
       value := ParamTable[1, i];
   END_IF

예시:

❌ 위험: value := ParamTable[1, i]; // 범위 검사 없음!

✅ 안전: IF 1, i >= 1 AND 1, i <= 10 THEN
value := ParamTable[1, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: TempSV[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := TempSV[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := TempSV[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := TempSV[i];
   END_IF

예시:

❌ 위험: value := TempSV[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := TempSV[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ParamTable[2, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 2, i >= 1 AND
      2, i <= 10 THEN
       value := ParamTable[2, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 2, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 2, i >= ARRAY_MIN AND 2, i <= ARRAY_MAX THEN
       value := ParamTable[2, i];
   END_IF

예시:

❌ 위험: value := ParamTable[2, i]; // 범위 검사 없음!

✅ 안전: IF 2, i >= 1 AND 2, i <= 10 THEN
value := ParamTable[2, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: TempSV[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := TempSV[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := TempSV[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := TempSV[i];
   END_IF

예시:

❌ 위험: value := TempSV[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := TempSV[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ParamTable[3, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 3, i >= 1 AND
      3, i <= 10 THEN
       value := ParamTable[3, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 3, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 3, i >= ARRAY_MIN AND 3, i <= ARRAY_MAX THEN
       value := ParamTable[3, i];
   END_IF

예시:

❌ 위험: value := ParamTable[3, i]; // 범위 검사 없음!

✅ 안전: IF 3, i >= 1 AND 3, i <= 10 THEN
value := ParamTable[3, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: TempSV[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := TempSV[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := TempSV[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := TempSV[i];
   END_IF

예시:

❌ 위험: value := TempSV[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := TempSV[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ParamTable[4, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 4, i >= 1 AND
      4, i <= 10 THEN
       value := ParamTable[4, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 4, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 4, i >= ARRAY_MIN AND 4, i <= ARRAY_MAX THEN
       value := ParamTable[4, i];
   END_IF

예시:

❌ 위험: value := ParamTable[4, i]; // 범위 검사 없음!

✅ 안전: IF 4, i >= 1 AND 4, i <= 10 THEN
value := ParamTable[4, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: TempSV[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := TempSV[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := TempSV[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := TempSV[i];
   END_IF

예시:

❌ 위험: value := TempSV[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := TempSV[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ParamTable[5, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 5, i >= 1 AND
      5, i <= 10 THEN
       value := ParamTable[5, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 5, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 5, i >= ARRAY_MIN AND 5, i <= ARRAY_MAX THEN
       value := ParamTable[5, i];
   END_IF

예시:

❌ 위험: value := ParamTable[5, i]; // 범위 검사 없음!

✅ 안전: IF 5, i >= 1 AND 5, i <= 10 THEN
value := ParamTable[5, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: TempSV[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := TempSV[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := TempSV[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := TempSV[i];
   END_IF

예시:

❌ 위험: value := TempSV[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := TempSV[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ParamTable[6, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 6, i >= 1 AND
      6, i <= 10 THEN
       value := ParamTable[6, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 6, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 6, i >= ARRAY_MIN AND 6, i <= ARRAY_MAX THEN
       value := ParamTable[6, i];
   END_IF

예시:

❌ 위험: value := ParamTable[6, i]; // 범위 검사 없음!

✅ 안전: IF 6, i >= 1 AND 6, i <= 10 THEN
value := ParamTable[6, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ValueTable[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ValueTable[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ValueTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ValueTable[i];
   END_IF

예시:

❌ 위험: value := ValueTable[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ValueTable[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ParamTable[1, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1, i >= 1 AND
      1, i <= 10 THEN
       value := ParamTable[1, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1, i >= ARRAY_MIN AND 1, i <= ARRAY_MAX THEN
       value := ParamTable[1, i];
   END_IF

예시:

❌ 위험: value := ParamTable[1, i]; // 범위 검사 없음!

✅ 안전: IF 1, i >= 1 AND 1, i <= 10 THEN
value := ParamTable[1, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ValueTable[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ValueTable[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ValueTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ValueTable[i];
   END_IF

예시:

❌ 위험: value := ValueTable[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ValueTable[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ParamTable[RangeNo, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF RangeNo, i >= 1 AND
      RangeNo, i <= 10 THEN
       value := ParamTable[RangeNo, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, RangeNo, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF RangeNo, i >= ARRAY_MIN AND RangeNo, i <= ARRAY_MAX THEN
       value := ParamTable[RangeNo, i];
   END_IF

예시:

❌ 위험: value := ParamTable[RangeNo, i]; // 범위 검사 없음!

✅ 안전: IF RangeNo, i >= 1 AND RangeNo, i <= 10 THEN
value := ParamTable[RangeNo, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ParamTable[RangeNo, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF RangeNo, i >= 1 AND
      RangeNo, i <= 10 THEN
       value := ParamTable[RangeNo, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, RangeNo, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF RangeNo, i >= ARRAY_MIN AND RangeNo, i <= ARRAY_MAX THEN
       value := ParamTable[RangeNo, i];
   END_IF

예시:

❌ 위험: value := ParamTable[RangeNo, i]; // 범위 검사 없음!

✅ 안전: IF RangeNo, i >= 1 AND RangeNo, i <= 10 THEN
value := ParamTable[RangeNo, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ParamTable[RangeNo + 1, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF RangeNo + 1, i >= 1 AND
      RangeNo + 1, i <= 10 THEN
       value := ParamTable[RangeNo + 1, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, RangeNo + 1, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF RangeNo + 1, i >= ARRAY_MIN AND RangeNo + 1, i <= ARRAY_MAX THEN
       value := ParamTable[RangeNo + 1, i];
   END_IF

예시:

❌ 위험: value := ParamTable[RangeNo + 1, i]; // 범위 검사 없음!

✅ 안전: IF RangeNo + 1, i >= 1 AND RangeNo + 1, i <= 10 THEN
value := ParamTable[RangeNo + 1, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: RangeTable[RangeNo]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF RangeNo >= 1 AND
      RangeNo <= 10 THEN
       value := RangeTable[RangeNo];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, RangeNo, 10);
   value := RangeTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF RangeNo >= ARRAY_MIN AND RangeNo <= ARRAY_MAX THEN
       value := RangeTable[RangeNo];
   END_IF

예시:

❌ 위험: value := RangeTable[RangeNo]; // 범위 검사 없음!

✅ 안전: IF RangeNo >= 1 AND RangeNo <= 10 THEN
value := RangeTable[RangeNo];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: RangeTable[RangeNo + 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF RangeNo + 1 >= 1 AND
      RangeNo + 1 <= 10 THEN
       value := RangeTable[RangeNo + 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, RangeNo + 1, 10);
   value := RangeTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF RangeNo + 1 >= ARRAY_MIN AND RangeNo + 1 <= ARRAY_MAX THEN
       value := RangeTable[RangeNo + 1];
   END_IF

예시:

❌ 위험: value := RangeTable[RangeNo + 1]; // 범위 검사 없음!

✅ 안전: IF RangeNo + 1 >= 1 AND RangeNo + 1 <= 10 THEN
value := RangeTable[RangeNo + 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: RangeTable[RangeNo + 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF RangeNo + 1 >= 1 AND
      RangeNo + 1 <= 10 THEN
       value := RangeTable[RangeNo + 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, RangeNo + 1, 10);
   value := RangeTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF RangeNo + 1 >= ARRAY_MIN AND RangeNo + 1 <= ARRAY_MAX THEN
       value := RangeTable[RangeNo + 1];
   END_IF

예시:

❌ 위험: value := RangeTable[RangeNo + 1]; // 범위 검사 없음!

✅ 안전: IF RangeNo + 1 >= 1 AND RangeNo + 1 <= 10 THEN
value := RangeTable[RangeNo + 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: RangeTable[RangeNo]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF RangeNo >= 1 AND
      RangeNo <= 10 THEN
       value := RangeTable[RangeNo];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, RangeNo, 10);
   value := RangeTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF RangeNo >= ARRAY_MIN AND RangeNo <= ARRAY_MAX THEN
       value := RangeTable[RangeNo];
   END_IF

예시:

❌ 위험: value := RangeTable[RangeNo]; // 범위 검사 없음!

✅ 안전: IF RangeNo >= 1 AND RangeNo <= 10 THEN
value := RangeTable[RangeNo];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ValueTable[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ValueTable[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ValueTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ValueTable[i];
   END_IF

예시:

❌ 위험: value := ValueTable[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ValueTable[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ParamTable[RangeNo, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF RangeNo, i >= 1 AND
      RangeNo, i <= 10 THEN
       value := ParamTable[RangeNo, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, RangeNo, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF RangeNo, i >= ARRAY_MIN AND RangeNo, i <= ARRAY_MAX THEN
       value := ParamTable[RangeNo, i];
   END_IF

예시:

❌ 위험: value := ParamTable[RangeNo, i]; // 범위 검사 없음!

✅ 안전: IF RangeNo, i >= 1 AND RangeNo, i <= 10 THEN
value := ParamTable[RangeNo, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: T_Angle[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := T_Angle[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := T_Angle[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := T_Angle[i];
   END_IF

예시:

❌ 위험: value := T_Angle[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := T_Angle[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: T_Angle[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := T_Angle[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := T_Angle[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := T_Angle[i];
   END_IF

예시:

❌ 위험: value := T_Angle[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := T_Angle[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: ValueTable[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ValueTable[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ValueTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ValueTable[i];
   END_IF

예시:

❌ 위험: value := ValueTable[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ValueTable[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: T_Angle[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := T_Angle[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := T_Angle[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := T_Angle[i];
   END_IF

예시:

❌ 위험: value := T_Angle[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := T_Angle[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: TempSV[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := TempSV[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := TempSV[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := TempSV[i];
   END_IF

예시:

❌ 위험: value := TempSV[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := TempSV[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: RangeNo = 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(RangeNo - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF RangeNo >= (0 - 1.0E-6) AND
      RangeNo <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF RangeNo >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(RangeNo * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF RangeNo = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(RangeNo - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: RangeNo = 6: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(RangeNo - 6) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF RangeNo >= (6 - 1.0E-6) AND
      RangeNo <= (6 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF RangeNo >= 6 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(RangeNo * 10.0);
   intTarget := REAL_TO_DINT(6 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF RangeNo = 6 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(RangeNo - 6) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: Range_1_Value <> 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Range_1_Value - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Range_1_Value >= (0 - 1.0E-6) AND
      Range_1_Value <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Range_1_Value >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Range_1_Value * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Range_1_Value = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Range_1_Value - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Range]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Range >= 1 AND
      1..cMAX_Heater_Range <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Range];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Range, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Range >= ARRAY_MIN AND 1..cMAX_Heater_Range <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Range];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Range]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Range >= 1 AND 1..cMAX_Heater_Range <= 10 THEN
value := ARRAY[1..cMAX_Heater_Range];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Range, 1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: TempSV[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := TempSV[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := TempSV[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := TempSV[i];
   END_IF

예시:

❌ 위험: value := TempSV[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := TempSV[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ParamTable[1, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1, i >= 1 AND
      1, i <= 10 THEN
       value := ParamTable[1, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1, i >= ARRAY_MIN AND 1, i <= ARRAY_MAX THEN
       value := ParamTable[1, i];
   END_IF

예시:

❌ 위험: value := ParamTable[1, i]; // 범위 검사 없음!

✅ 안전: IF 1, i >= 1 AND 1, i <= 10 THEN
value := ParamTable[1, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: TempSV[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := TempSV[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := TempSV[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := TempSV[i];
   END_IF

예시:

❌ 위험: value := TempSV[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := TempSV[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ParamTable[2, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 2, i >= 1 AND
      2, i <= 10 THEN
       value := ParamTable[2, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 2, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 2, i >= ARRAY_MIN AND 2, i <= ARRAY_MAX THEN
       value := ParamTable[2, i];
   END_IF

예시:

❌ 위험: value := ParamTable[2, i]; // 범위 검사 없음!

✅ 안전: IF 2, i >= 1 AND 2, i <= 10 THEN
value := ParamTable[2, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: TempSV[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := TempSV[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := TempSV[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := TempSV[i];
   END_IF

예시:

❌ 위험: value := TempSV[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := TempSV[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ParamTable[3, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 3, i >= 1 AND
      3, i <= 10 THEN
       value := ParamTable[3, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 3, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 3, i >= ARRAY_MIN AND 3, i <= ARRAY_MAX THEN
       value := ParamTable[3, i];
   END_IF

예시:

❌ 위험: value := ParamTable[3, i]; // 범위 검사 없음!

✅ 안전: IF 3, i >= 1 AND 3, i <= 10 THEN
value := ParamTable[3, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: TempSV[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := TempSV[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := TempSV[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := TempSV[i];
   END_IF

예시:

❌ 위험: value := TempSV[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := TempSV[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ParamTable[4, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 4, i >= 1 AND
      4, i <= 10 THEN
       value := ParamTable[4, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 4, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 4, i >= ARRAY_MIN AND 4, i <= ARRAY_MAX THEN
       value := ParamTable[4, i];
   END_IF

예시:

❌ 위험: value := ParamTable[4, i]; // 범위 검사 없음!

✅ 안전: IF 4, i >= 1 AND 4, i <= 10 THEN
value := ParamTable[4, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: TempSV[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := TempSV[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := TempSV[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := TempSV[i];
   END_IF

예시:

❌ 위험: value := TempSV[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := TempSV[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ParamTable[5, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 5, i >= 1 AND
      5, i <= 10 THEN
       value := ParamTable[5, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 5, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 5, i >= ARRAY_MIN AND 5, i <= ARRAY_MAX THEN
       value := ParamTable[5, i];
   END_IF

예시:

❌ 위험: value := ParamTable[5, i]; // 범위 검사 없음!

✅ 안전: IF 5, i >= 1 AND 5, i <= 10 THEN
value := ParamTable[5, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: TempSV[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := TempSV[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := TempSV[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := TempSV[i];
   END_IF

예시:

❌ 위험: value := TempSV[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := TempSV[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ParamTable[6, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 6, i >= 1 AND
      6, i <= 10 THEN
       value := ParamTable[6, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 6, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 6, i >= ARRAY_MIN AND 6, i <= ARRAY_MAX THEN
       value := ParamTable[6, i];
   END_IF

예시:

❌ 위험: value := ParamTable[6, i]; // 범위 검사 없음!

✅ 안전: IF 6, i >= 1 AND 6, i <= 10 THEN
value := ParamTable[6, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ValueTable[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ValueTable[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ValueTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ValueTable[i];
   END_IF

예시:

❌ 위험: value := ValueTable[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ValueTable[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ParamTable[1, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1, i >= 1 AND
      1, i <= 10 THEN
       value := ParamTable[1, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1, i >= ARRAY_MIN AND 1, i <= ARRAY_MAX THEN
       value := ParamTable[1, i];
   END_IF

예시:

❌ 위험: value := ParamTable[1, i]; // 범위 검사 없음!

✅ 안전: IF 1, i >= 1 AND 1, i <= 10 THEN
value := ParamTable[1, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ValueTable[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ValueTable[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ValueTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ValueTable[i];
   END_IF

예시:

❌ 위험: value := ValueTable[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ValueTable[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ParamTable[RangeNo, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF RangeNo, i >= 1 AND
      RangeNo, i <= 10 THEN
       value := ParamTable[RangeNo, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, RangeNo, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF RangeNo, i >= ARRAY_MIN AND RangeNo, i <= ARRAY_MAX THEN
       value := ParamTable[RangeNo, i];
   END_IF

예시:

❌ 위험: value := ParamTable[RangeNo, i]; // 범위 검사 없음!

✅ 안전: IF RangeNo, i >= 1 AND RangeNo, i <= 10 THEN
value := ParamTable[RangeNo, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ParamTable[RangeNo, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF RangeNo, i >= 1 AND
      RangeNo, i <= 10 THEN
       value := ParamTable[RangeNo, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, RangeNo, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF RangeNo, i >= ARRAY_MIN AND RangeNo, i <= ARRAY_MAX THEN
       value := ParamTable[RangeNo, i];
   END_IF

예시:

❌ 위험: value := ParamTable[RangeNo, i]; // 범위 검사 없음!

✅ 안전: IF RangeNo, i >= 1 AND RangeNo, i <= 10 THEN
value := ParamTable[RangeNo, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ParamTable[RangeNo + 1, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF RangeNo + 1, i >= 1 AND
      RangeNo + 1, i <= 10 THEN
       value := ParamTable[RangeNo + 1, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, RangeNo + 1, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF RangeNo + 1, i >= ARRAY_MIN AND RangeNo + 1, i <= ARRAY_MAX THEN
       value := ParamTable[RangeNo + 1, i];
   END_IF

예시:

❌ 위험: value := ParamTable[RangeNo + 1, i]; // 범위 검사 없음!

✅ 안전: IF RangeNo + 1, i >= 1 AND RangeNo + 1, i <= 10 THEN
value := ParamTable[RangeNo + 1, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: RangeTable[RangeNo]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF RangeNo >= 1 AND
      RangeNo <= 10 THEN
       value := RangeTable[RangeNo];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, RangeNo, 10);
   value := RangeTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF RangeNo >= ARRAY_MIN AND RangeNo <= ARRAY_MAX THEN
       value := RangeTable[RangeNo];
   END_IF

예시:

❌ 위험: value := RangeTable[RangeNo]; // 범위 검사 없음!

✅ 안전: IF RangeNo >= 1 AND RangeNo <= 10 THEN
value := RangeTable[RangeNo];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: RangeTable[RangeNo + 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF RangeNo + 1 >= 1 AND
      RangeNo + 1 <= 10 THEN
       value := RangeTable[RangeNo + 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, RangeNo + 1, 10);
   value := RangeTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF RangeNo + 1 >= ARRAY_MIN AND RangeNo + 1 <= ARRAY_MAX THEN
       value := RangeTable[RangeNo + 1];
   END_IF

예시:

❌ 위험: value := RangeTable[RangeNo + 1]; // 범위 검사 없음!

✅ 안전: IF RangeNo + 1 >= 1 AND RangeNo + 1 <= 10 THEN
value := RangeTable[RangeNo + 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: RangeTable[RangeNo + 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF RangeNo + 1 >= 1 AND
      RangeNo + 1 <= 10 THEN
       value := RangeTable[RangeNo + 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, RangeNo + 1, 10);
   value := RangeTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF RangeNo + 1 >= ARRAY_MIN AND RangeNo + 1 <= ARRAY_MAX THEN
       value := RangeTable[RangeNo + 1];
   END_IF

예시:

❌ 위험: value := RangeTable[RangeNo + 1]; // 범위 검사 없음!

✅ 안전: IF RangeNo + 1 >= 1 AND RangeNo + 1 <= 10 THEN
value := RangeTable[RangeNo + 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: RangeTable[RangeNo]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF RangeNo >= 1 AND
      RangeNo <= 10 THEN
       value := RangeTable[RangeNo];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, RangeNo, 10);
   value := RangeTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF RangeNo >= ARRAY_MIN AND RangeNo <= ARRAY_MAX THEN
       value := RangeTable[RangeNo];
   END_IF

예시:

❌ 위험: value := RangeTable[RangeNo]; // 범위 검사 없음!

✅ 안전: IF RangeNo >= 1 AND RangeNo <= 10 THEN
value := RangeTable[RangeNo];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ValueTable[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ValueTable[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ValueTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ValueTable[i];
   END_IF

예시:

❌ 위험: value := ValueTable[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ValueTable[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ParamTable[RangeNo, i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF RangeNo, i >= 1 AND
      RangeNo, i <= 10 THEN
       value := ParamTable[RangeNo, i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, RangeNo, i, 10);
   value := ParamTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF RangeNo, i >= ARRAY_MIN AND RangeNo, i <= ARRAY_MAX THEN
       value := ParamTable[RangeNo, i];
   END_IF

예시:

❌ 위험: value := ParamTable[RangeNo, i]; // 범위 검사 없음!

✅ 안전: IF RangeNo, i >= 1 AND RangeNo, i <= 10 THEN
value := ParamTable[RangeNo, i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: T_Angle[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := T_Angle[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := T_Angle[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := T_Angle[i];
   END_IF

예시:

❌ 위험: value := T_Angle[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := T_Angle[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: T_Angle[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := T_Angle[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := T_Angle[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := T_Angle[i];
   END_IF

예시:

❌ 위험: value := T_Angle[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := T_Angle[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: ValueTable[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ValueTable[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ValueTable[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ValueTable[i];
   END_IF

예시:

❌ 위험: value := ValueTable[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ValueTable[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: T_Angle[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := T_Angle[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := T_Angle[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := T_Angle[i];
   END_IF

예시:

❌ 위험: value := T_Angle[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := T_Angle[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: TempSV[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := TempSV[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := TempSV[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := TempSV[i];
   END_IF

예시:

❌ 위험: value := TempSV[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := TempSV[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Add_EventLog_buffer.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Add_EventLog_buffer.TcPOU:1

설명: Event_Msg_Old <> Msg: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Event_Msg_Old - Msg) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Event_Msg_Old >= (Msg - 1.0E-6) AND
      Event_Msg_Old <= (Msg + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Event_Msg_Old >= Msg THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Event_Msg_Old * 10.0);
   intTarget := REAL_TO_DINT(Msg * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Event_Msg_Old = Msg THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Event_Msg_Old - Msg) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Add_EventLog_buffer.TcPOU:1

설명: i = cMAX_Event_Log_Buffer: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(i - cMAX_Event_Log_Buffer) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF i >= (cMAX_Event_Log_Buffer - 1.0E-6) AND
      i <= (cMAX_Event_Log_Buffer + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF i >= cMAX_Event_Log_Buffer THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(i * 10.0);
   intTarget := REAL_TO_DINT(cMAX_Event_Log_Buffer * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF i = cMAX_Event_Log_Buffer THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(i - cMAX_Event_Log_Buffer) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Add_EventLog_buffer.TcPOU:1

설명: ARRAY[1..cMAX_Event_Log_Buffer]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Event_Log_Buffer >= 1 AND
      1..cMAX_Event_Log_Buffer <= 10 THEN
       value := ARRAY[1..cMAX_Event_Log_Buffer];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Event_Log_Buffer, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Event_Log_Buffer >= ARRAY_MIN AND 1..cMAX_Event_Log_Buffer <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Event_Log_Buffer];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Event_Log_Buffer]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Event_Log_Buffer >= 1 AND 1..cMAX_Event_Log_Buffer <= 10 THEN
value := ARRAY[1..cMAX_Event_Log_Buffer];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Add_EventLog_buffer.TcPOU:1

설명: l_Data[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := l_Data[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := l_Data[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := l_Data[i];
   END_IF

예시:

❌ 위험: value := l_Data[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := l_Data[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Add_EventLog_buffer.TcPOU:1

설명: l_Data[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := l_Data[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := l_Data[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := l_Data[i];
   END_IF

예시:

❌ 위험: value := l_Data[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := l_Data[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_CheckMainZone.TcPOU:1

설명: eDesc_Heater_OutMode: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_Heater_OutMode <> NULL THEN
       value := eDesc_Heater_OutMode^;
       // 또는 eDesc_Heater_OutMode.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_Heater_OutMode');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_Heater_OutMode) THEN
       value := eDesc_Heater_OutMode.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_Heater_OutMode := ADR(targetVariable);
   IF eDesc_Heater_OutMode = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_Heater_OutMode = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_Heater_OutMode^; // NULL 체크 없음!
value := eDesc_Heater_OutMode.member; // NULL 체크 없음!

✅ 안전: IF eDesc_Heater_OutMode <> NULL THEN
value := eDesc_Heater_OutMode^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_Heater_OutMode) THEN
value := eDesc_Heater_OutMode.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_CheckMainZone.TcPOU:1

설명: eDesc_Heater_OutMode: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_Heater_OutMode <> NULL THEN
       value := eDesc_Heater_OutMode^;
       // 또는 eDesc_Heater_OutMode.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_Heater_OutMode');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_Heater_OutMode) THEN
       value := eDesc_Heater_OutMode.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_Heater_OutMode := ADR(targetVariable);
   IF eDesc_Heater_OutMode = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_Heater_OutMode = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_Heater_OutMode^; // NULL 체크 없음!
value := eDesc_Heater_OutMode.member; // NULL 체크 없음!

✅ 안전: IF eDesc_Heater_OutMode <> NULL THEN
value := eDesc_Heater_OutMode^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_Heater_OutMode) THEN
value := eDesc_Heater_OutMode.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_CheckMainZone.TcPOU:1

설명: eDesc_Heater_OutMode: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_Heater_OutMode <> NULL THEN
       value := eDesc_Heater_OutMode^;
       // 또는 eDesc_Heater_OutMode.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_Heater_OutMode');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_Heater_OutMode) THEN
       value := eDesc_Heater_OutMode.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_Heater_OutMode := ADR(targetVariable);
   IF eDesc_Heater_OutMode = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_Heater_OutMode = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_Heater_OutMode^; // NULL 체크 없음!
value := eDesc_Heater_OutMode.member; // NULL 체크 없음!

✅ 안전: IF eDesc_Heater_OutMode <> NULL THEN
value := eDesc_Heater_OutMode^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_Heater_OutMode) THEN
value := eDesc_Heater_OutMode.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_CheckMainZone.TcPOU:1

설명: eDesc_Heater_OutMode: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_Heater_OutMode <> NULL THEN
       value := eDesc_Heater_OutMode^;
       // 또는 eDesc_Heater_OutMode.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_Heater_OutMode');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_Heater_OutMode) THEN
       value := eDesc_Heater_OutMode.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_Heater_OutMode := ADR(targetVariable);
   IF eDesc_Heater_OutMode = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_Heater_OutMode = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_Heater_OutMode^; // NULL 체크 없음!
value := eDesc_Heater_OutMode.member; // NULL 체크 없음!

✅ 안전: IF eDesc_Heater_OutMode <> NULL THEN
value := eDesc_Heater_OutMode^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_Heater_OutMode) THEN
value := eDesc_Heater_OutMode.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_CheckMainZone.TcPOU:1

설명: eDesc_Heater_OutMode: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_Heater_OutMode <> NULL THEN
       value := eDesc_Heater_OutMode^;
       // 또는 eDesc_Heater_OutMode.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_Heater_OutMode');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_Heater_OutMode) THEN
       value := eDesc_Heater_OutMode.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_Heater_OutMode := ADR(targetVariable);
   IF eDesc_Heater_OutMode = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_Heater_OutMode = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_Heater_OutMode^; // NULL 체크 없음!
value := eDesc_Heater_OutMode.member; // NULL 체크 없음!

✅ 안전: IF eDesc_Heater_OutMode <> NULL THEN
value := eDesc_Heater_OutMode^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_Heater_OutMode) THEN
value := eDesc_Heater_OutMode.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_CheckMainZone.TcPOU:1

설명: eDesc_Heater_OutMode: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_Heater_OutMode <> NULL THEN
       value := eDesc_Heater_OutMode^;
       // 또는 eDesc_Heater_OutMode.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_Heater_OutMode');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_Heater_OutMode) THEN
       value := eDesc_Heater_OutMode.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_Heater_OutMode := ADR(targetVariable);
   IF eDesc_Heater_OutMode = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_Heater_OutMode = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_Heater_OutMode^; // NULL 체크 없음!
value := eDesc_Heater_OutMode.member; // NULL 체크 없음!

✅ 안전: IF eDesc_Heater_OutMode <> NULL THEN
value := eDesc_Heater_OutMode^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_Heater_OutMode) THEN
value := eDesc_Heater_OutMode.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: 0 = Jump_Step: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(0 - Jump_Step) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF 0 >= (Jump_Step - 1.0E-6) AND
      0 <= (Jump_Step + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF 0 >= Jump_Step THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(0 * 10.0);
   intTarget := REAL_TO_DINT(Jump_Step * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF 0 = Jump_Step THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(0 - Jump_Step) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: StepCount[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := StepCount[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := StepCount[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := StepCount[i];
   END_IF

예시:

❌ 위험: value := StepCount[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := StepCount[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: StepCount[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := StepCount[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := StepCount[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := StepCount[i];
   END_IF

예시:

❌ 위험: value := StepCount[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := StepCount[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: ApcSuccessJump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ApcSuccessJump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ApcSuccessJump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ApcSuccessJump_Step[i];
   END_IF

예시:

❌ 위험: value := ApcSuccessJump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ApcSuccessJump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: ApcSuccessJump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ApcSuccessJump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ApcSuccessJump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ApcSuccessJump_Step[i];
   END_IF

예시:

❌ 위험: value := ApcSuccessJump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ApcSuccessJump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: Jump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Jump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Jump_Step[i];
   END_IF

예시:

❌ 위험: value := Jump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Jump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: Jump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Jump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Jump_Step[i];
   END_IF

예시:

❌ 위험: value := Jump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Jump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: ApcSuccessJump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ApcSuccessJump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ApcSuccessJump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ApcSuccessJump_Step[i];
   END_IF

예시:

❌ 위험: value := ApcSuccessJump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ApcSuccessJump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: ApcSuccessJump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ApcSuccessJump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ApcSuccessJump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ApcSuccessJump_Step[i];
   END_IF

예시:

❌ 위험: value := ApcSuccessJump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ApcSuccessJump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: Jump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Jump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Jump_Step[i];
   END_IF

예시:

❌ 위험: value := Jump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Jump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: Jump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Jump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Jump_Step[i];
   END_IF

예시:

❌ 위험: value := Jump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Jump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: Jump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Jump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Jump_Step[i];
   END_IF

예시:

❌ 위험: value := Jump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Jump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: Jump_Step[Start]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Start >= 1 AND
      Start <= 10 THEN
       value := Jump_Step[Start];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Start, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Start >= ARRAY_MIN AND Start <= ARRAY_MAX THEN
       value := Jump_Step[Start];
   END_IF

예시:

❌ 위험: value := Jump_Step[Start]; // 범위 검사 없음!

✅ 안전: IF Start >= 1 AND Start <= 10 THEN
value := Jump_Step[Start];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: Jump_Step[End - 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF End - 1 >= 1 AND
      End - 1 <= 10 THEN
       value := Jump_Step[End - 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, End - 1, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF End - 1 >= ARRAY_MIN AND End - 1 <= ARRAY_MAX THEN
       value := Jump_Step[End - 1];
   END_IF

예시:

❌ 위험: value := Jump_Step[End - 1]; // 범위 검사 없음!

✅ 안전: IF End - 1 >= 1 AND End - 1 <= 10 THEN
value := Jump_Step[End - 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: Jump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Jump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Jump_Step[i];
   END_IF

예시:

❌ 위험: value := Jump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Jump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: Jump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Jump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Jump_Step[i];
   END_IF

예시:

❌ 위험: value := Jump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Jump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: 0 = Jump_Step: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(0 - Jump_Step) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF 0 >= (Jump_Step - 1.0E-6) AND
      0 <= (Jump_Step + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF 0 >= Jump_Step THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(0 * 10.0);
   intTarget := REAL_TO_DINT(Jump_Step * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF 0 = Jump_Step THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(0 - Jump_Step) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: StepCount[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := StepCount[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := StepCount[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := StepCount[i];
   END_IF

예시:

❌ 위험: value := StepCount[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := StepCount[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: StepCount[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := StepCount[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := StepCount[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := StepCount[i];
   END_IF

예시:

❌ 위험: value := StepCount[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := StepCount[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: ApcSuccessJump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ApcSuccessJump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ApcSuccessJump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ApcSuccessJump_Step[i];
   END_IF

예시:

❌ 위험: value := ApcSuccessJump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ApcSuccessJump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: ApcSuccessJump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ApcSuccessJump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ApcSuccessJump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ApcSuccessJump_Step[i];
   END_IF

예시:

❌ 위험: value := ApcSuccessJump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ApcSuccessJump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: Jump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Jump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Jump_Step[i];
   END_IF

예시:

❌ 위험: value := Jump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Jump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: Jump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Jump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Jump_Step[i];
   END_IF

예시:

❌ 위험: value := Jump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Jump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: ApcSuccessJump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ApcSuccessJump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ApcSuccessJump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ApcSuccessJump_Step[i];
   END_IF

예시:

❌ 위험: value := ApcSuccessJump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ApcSuccessJump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: ApcSuccessJump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ApcSuccessJump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ApcSuccessJump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ApcSuccessJump_Step[i];
   END_IF

예시:

❌ 위험: value := ApcSuccessJump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ApcSuccessJump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: Jump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Jump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Jump_Step[i];
   END_IF

예시:

❌ 위험: value := Jump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Jump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: Jump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Jump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Jump_Step[i];
   END_IF

예시:

❌ 위험: value := Jump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Jump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: Jump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Jump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Jump_Step[i];
   END_IF

예시:

❌ 위험: value := Jump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Jump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: Jump_Step[Start]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Start >= 1 AND
      Start <= 10 THEN
       value := Jump_Step[Start];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Start, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Start >= ARRAY_MIN AND Start <= ARRAY_MAX THEN
       value := Jump_Step[Start];
   END_IF

예시:

❌ 위험: value := Jump_Step[Start]; // 범위 검사 없음!

✅ 안전: IF Start >= 1 AND Start <= 10 THEN
value := Jump_Step[Start];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: Jump_Step[End - 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF End - 1 >= 1 AND
      End - 1 <= 10 THEN
       value := Jump_Step[End - 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, End - 1, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF End - 1 >= ARRAY_MIN AND End - 1 <= ARRAY_MAX THEN
       value := Jump_Step[End - 1];
   END_IF

예시:

❌ 위험: value := Jump_Step[End - 1]; // 범위 검사 없음!

✅ 안전: IF End - 1 >= 1 AND End - 1 <= 10 THEN
value := Jump_Step[End - 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: Jump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Jump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Jump_Step[i];
   END_IF

예시:

❌ 위험: value := Jump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Jump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: Jump_Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Jump_Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Jump_Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Jump_Step[i];
   END_IF

예시:

❌ 위험: value := Jump_Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Jump_Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_APC_PID.TcPOU:1

설명: iPrecision = 2: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iPrecision - 2) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iPrecision >= (2 - 1.0E-6) AND
      iPrecision <= (2 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iPrecision >= 2 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iPrecision * 10.0);
   intTarget := REAL_TO_DINT(2 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iPrecision = 2 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iPrecision - 2) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Extract_Array.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Extract_Array.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Extract_Array.TcPOU:1

설명: Data[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := Data[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := Data[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := Data[Loop];
   END_IF

예시:

❌ 위험: value := Data[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := Data[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Extract_Array.TcPOU:1

설명: Data[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := Data[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := Data[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := Data[Loop];
   END_IF

예시:

❌ 위험: value := Data[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := Data[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Read_Array.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Read_Array.TcPOU:1

설명: iRead[Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Index >= 1 AND
      Index <= 10 THEN
       value := iRead[Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Index, 10);
   value := iRead[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Index >= ARRAY_MIN AND Index <= ARRAY_MAX THEN
       value := iRead[Index];
   END_IF

예시:

❌ 위험: value := iRead[Index]; // 범위 검사 없음!

✅ 안전: IF Index >= 1 AND Index <= 10 THEN
value := iRead[Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Write_Array.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Write_Array.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Write_Array.TcPOU:1

설명: iWrite[Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Index >= 1 AND
      Index <= 10 THEN
       value := iWrite[Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Index, 10);
   value := iWrite[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Index >= ARRAY_MIN AND Index <= ARRAY_MAX THEN
       value := iWrite[Index];
   END_IF

예시:

❌ 위험: value := iWrite[Index]; // 범위 검사 없음!

✅ 안전: IF Index >= 1 AND Index <= 10 THEN
value := iWrite[Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Write_Array.TcPOU:1

설명: iData[Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Index >= 1 AND
      Index <= 10 THEN
       value := iData[Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Index, 10);
   value := iData[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Index >= ARRAY_MIN AND Index <= ARRAY_MAX THEN
       value := iData[Index];
   END_IF

예시:

❌ 위험: value := iData[Index]; // 범위 검사 없음!

✅ 안전: IF Index >= 1 AND Index <= 10 THEN
value := iData[Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Write_Array.TcPOU:1

설명: iData[Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Index >= 1 AND
      Index <= 10 THEN
       value := iData[Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Index, 10);
   value := iData[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Index >= ARRAY_MIN AND Index <= ARRAY_MAX THEN
       value := iData[Index];
   END_IF

예시:

❌ 위험: value := iData[Index]; // 범위 검사 없음!

✅ 안전: IF Index >= 1 AND Index <= 10 THEN
value := iData[Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_EventLog_Shift.TcPOU:1

설명: ARRAY[1..100]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..100 >= 1 AND
      1..100 <= 10 THEN
       value := ARRAY[1..100];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..100, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..100 >= ARRAY_MIN AND 1..100 <= ARRAY_MAX THEN
       value := ARRAY[1..100];
   END_IF

예시:

❌ 위험: value := ARRAY[1..100]; // 범위 검사 없음!

✅ 안전: IF 1..100 >= 1 AND 1..100 <= 10 THEN
value := ARRAY[1..100];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_EventLog_Shift.TcPOU:1

설명: ARRAY[0..3]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 0..3 >= 1 AND
      0..3 <= 10 THEN
       value := ARRAY[0..3];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 0..3, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 0..3 >= ARRAY_MIN AND 0..3 <= ARRAY_MAX THEN
       value := ARRAY[0..3];
   END_IF

예시:

❌ 위험: value := ARRAY[0..3]; // 범위 검사 없음!

✅ 안전: IF 0..3 >= 1 AND 0..3 <= 10 THEN
value := ARRAY[0..3];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_EventLog_Shift.TcPOU:1

설명: sData[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := sData[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := sData[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := sData[i];
   END_IF

예시:

❌ 위험: value := sData[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := sData[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_EventLog_Shift.TcPOU:1

설명: sData[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := sData[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := sData[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := sData[i];
   END_IF

예시:

❌ 위험: value := sData[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := sData[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_EventLog_Shift.TcPOU:1

설명: sData[i + 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i + 1 >= 1 AND
      i + 1 <= 10 THEN
       value := sData[i + 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i + 1, 10);
   value := sData[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i + 1 >= ARRAY_MIN AND i + 1 <= ARRAY_MAX THEN
       value := sData[i + 1];
   END_IF

예시:

❌ 위험: value := sData[i + 1]; // 범위 검사 없음!

✅ 안전: IF i + 1 >= 1 AND i + 1 <= 10 THEN
value := sData[i + 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_FFU_CheckSum_Send.TcPOU:1

설명: ARRAY[0..8]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 0..8 >= 1 AND
      0..8 <= 10 THEN
       value := ARRAY[0..8];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 0..8, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 0..8 >= ARRAY_MIN AND 0..8 <= ARRAY_MAX THEN
       value := ARRAY[0..8];
   END_IF

예시:

❌ 위험: value := ARRAY[0..8]; // 범위 검사 없음!

✅ 안전: IF 0..8 >= 1 AND 0..8 <= 10 THEN
value := ARRAY[0..8];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_FFU_CheckSum_Send.TcPOU:1

설명: iData[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := iData[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := iData[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := iData[Loop];
   END_IF

예시:

❌ 위험: value := iData[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := iData[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_FFU_CheckSum_Send.TcPOU:1

설명: AX_CRC16_Table[((x_crc XOR x_byte) AND 16#00FF) + 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF ((x_crc XOR x_byte) AND 16#00FF) + 1 >= 1 AND
      ((x_crc XOR x_byte) AND 16#00FF) + 1 <= 10 THEN
       value := AX_CRC16_Table[((x_crc XOR x_byte) AND 16#00FF) + 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, ((x_crc XOR x_byte) AND 16#00FF) + 1, 10);
   value := AX_CRC16_Table[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF ((x_crc XOR x_byte) AND 16#00FF) + 1 >= ARRAY_MIN AND ((x_crc XOR x_byte) AND 16#00FF) + 1 <= ARRAY_MAX THEN
       value := AX_CRC16_Table[((x_crc XOR x_byte) AND 16#00FF) + 1];
   END_IF

예시:

❌ 위험: value := AX_CRC16_Table[((x_crc XOR x_byte) AND 16#00FF) + 1]; // 범위 검사 없음!

✅ 안전: IF ((x_crc XOR x_byte) AND 16#00FF) + 1 >= 1 AND ((x_crc XOR x_byte) AND 16#00FF) + 1 <= 10 THEN
value := AX_CRC16_Table[((x_crc XOR x_byte) AND 16#00FF) + 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Get_Parameter.TcPOU:1

설명: findName = destName: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(findName - destName) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF findName >= (destName - 1.0E-6) AND
      findName <= (destName + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF findName >= destName THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(findName * 10.0);
   intTarget := REAL_TO_DINT(destName * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF findName = destName THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(findName - destName) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Get_Parameter.TcPOU:1

설명: findName = name: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(findName - name) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF findName >= (name - 1.0E-6) AND
      findName <= (name + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF findName >= name THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(findName * 10.0);
   intTarget := REAL_TO_DINT(name * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF findName = name THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(findName - name) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Func.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Func.TcPOU:1

설명: ARRAY[1..8]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..8 >= 1 AND
      1..8 <= 10 THEN
       value := ARRAY[1..8];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..8, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..8 >= ARRAY_MIN AND 1..8 <= ARRAY_MAX THEN
       value := ARRAY[1..8];
   END_IF

예시:

❌ 위험: value := ARRAY[1..8]; // 범위 검사 없음!

✅ 안전: IF 1..8 >= 1 AND 1..8 <= 10 THEN
value := ARRAY[1..8];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Process.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Process.TcPOU:1

설명: SYS_TrendData: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF SYS_TrendData <> NULL THEN
       value := SYS_TrendData^;
       // 또는 SYS_TrendData.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: SYS_TrendData');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(SYS_TrendData) THEN
       value := SYS_TrendData.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   SYS_TrendData := ADR(targetVariable);
   IF SYS_TrendData = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF SYS_TrendData = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := SYS_TrendData^; // NULL 체크 없음!
value := SYS_TrendData.member; // NULL 체크 없음!

✅ 안전: IF SYS_TrendData <> NULL THEN
value := SYS_TrendData^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(SYS_TrendData) THEN
value := SYS_TrendData.member;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Process.TcPOU:1

설명: ARRAY[1..cMAX_Mars_Info]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Mars_Info >= 1 AND
      1..cMAX_Mars_Info <= 10 THEN
       value := ARRAY[1..cMAX_Mars_Info];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Mars_Info, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Mars_Info >= ARRAY_MIN AND 1..cMAX_Mars_Info <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Mars_Info];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Mars_Info]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Mars_Info >= 1 AND 1..cMAX_Mars_Info <= 10 THEN
value := ARRAY[1..cMAX_Mars_Info];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Process.TcPOU:1

설명: l_Data[Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Index >= 1 AND
      Index <= 10 THEN
       value := l_Data[Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Index, 10);
   value := l_Data[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Index >= ARRAY_MIN AND Index <= ARRAY_MAX THEN
       value := l_Data[Index];
   END_IF

예시:

❌ 위험: value := l_Data[Index]; // 범위 검사 없음!

✅ 안전: IF Index >= 1 AND Index <= 10 THEN
value := l_Data[Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Parameter_Check.TcPOU:1

설명: findName = name: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(findName - name) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF findName >= (name - 1.0E-6) AND
      findName <= (name + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF findName >= name THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(findName * 10.0);
   intTarget := REAL_TO_DINT(name * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF findName = name THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(findName - name) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_RealRound.TcPOU:1

설명: 10: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 10 <> NULL THEN
       value := 10^;
       // 또는 10.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 10');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(10) THEN
       value := 10.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   10 := ADR(targetVariable);
   IF 10 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 10 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 10^; // NULL 체크 없음!
value := 10.member; // NULL 체크 없음!

✅ 안전: IF 10 <> NULL THEN
value := 10^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(10) THEN
value := 10.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_RealRound.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_RealRound.TcPOU:1

설명: 10: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 10 <> NULL THEN
       value := 10^;
       // 또는 10.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 10');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(10) THEN
       value := 10.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   10 := ADR(targetVariable);
   IF 10 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 10 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 10^; // NULL 체크 없음!
value := 10.member; // NULL 체크 없음!

✅ 안전: IF 10 <> NULL THEN
value := 10^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(10) THEN
value := 10.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Set_Parameter.TcPOU:1

설명: srcName = destName: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(srcName - destName) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF srcName >= (destName - 1.0E-6) AND
      srcName <= (destName + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF srcName >= destName THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(srcName * 10.0);
   intTarget := REAL_TO_DINT(destName * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF srcName = destName THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(srcName - destName) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_StepName_Search.TcPOU:1

설명: 0 = LEN: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(0 - LEN) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF 0 >= (LEN - 1.0E-6) AND
      0 <= (LEN + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF 0 >= LEN THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(0 * 10.0);
   intTarget := REAL_TO_DINT(LEN * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF 0 = LEN THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(0 - LEN) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_StepName_Search.TcPOU:1

설명: searchName = SX_INF_Process_StepName: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(searchName - SX_INF_Process_StepName) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF searchName >= (SX_INF_Process_StepName - 1.0E-6) AND
      searchName <= (SX_INF_Process_StepName + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF searchName >= SX_INF_Process_StepName THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(searchName * 10.0);
   intTarget := REAL_TO_DINT(SX_INF_Process_StepName * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF searchName = SX_INF_Process_StepName THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(searchName - SX_INF_Process_StepName) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_StepName_Search.TcPOU:1

설명: SX_INF_Process_StepName[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := SX_INF_Process_StepName[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := SX_INF_Process_StepName[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := SX_INF_Process_StepName[i];
   END_IF

예시:

❌ 위험: value := SX_INF_Process_StepName[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := SX_INF_Process_StepName[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\Get_IEEE754.TcPOU:1

설명: ARRAY[0..3]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 0..3 >= 1 AND
      0..3 <= 10 THEN
       value := ARRAY[0..3];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 0..3, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 0..3 >= ARRAY_MIN AND 0..3 <= ARRAY_MAX THEN
       value := ARRAY[0..3];
   END_IF

예시:

❌ 위험: value := ARRAY[0..3]; // 범위 검사 없음!

✅ 안전: IF 0..3 >= 1 AND 0..3 <= 10 THEN
value := ARRAY[0..3];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\Get_IEEE754.TcPOU:1

설명: data[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := data[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := data[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := data[i];
   END_IF

예시:

❌ 위험: value := data[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := data[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\Get_IEEE754.TcPOU:1

설명: data[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := data[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := data[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := data[i];
   END_IF

예시:

❌ 위험: value := data[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := data[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_ROUND.TcPOU:1

설명: 10: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 10 <> NULL THEN
       value := 10^;
       // 또는 10.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 10');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(10) THEN
       value := 10.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   10 := ADR(targetVariable);
   IF 10 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 10 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 10^; // NULL 체크 없음!
value := 10.member; // NULL 체크 없음!

✅ 안전: IF 10 <> NULL THEN
value := 10^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(10) THEN
value := 10.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_ROUND.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_ROUND.TcPOU:1

설명: 10: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 10 <> NULL THEN
       value := 10^;
       // 또는 10.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 10');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(10) THEN
       value := 10.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   10 := ADR(targetVariable);
   IF 10 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 10 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 10^; // NULL 체크 없음!
value := 10.member; // NULL 체크 없음!

✅ 안전: IF 10 <> NULL THEN
value := 10^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(10) THEN
value := 10.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_ROUND.TcPOU:1

설명: 10: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 10 <> NULL THEN
       value := 10^;
       // 또는 10.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 10');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(10) THEN
       value := 10.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   10 := ADR(targetVariable);
   IF 10 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 10 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 10^; // NULL 체크 없음!
value := 10.member; // NULL 체크 없음!

✅ 안전: IF 10 <> NULL THEN
value := 10^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(10) THEN
value := 10.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_ROUND.TcPOU:1

설명: 10: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 10 <> NULL THEN
       value := 10^;
       // 또는 10.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 10');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(10) THEN
       value := 10.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   10 := ADR(targetVariable);
   IF 10 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 10 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 10^; // NULL 체크 없음!
value := 10.member; // NULL 체크 없음!

✅ 안전: IF 10 <> NULL THEN
value := 10^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(10) THEN
value := 10.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_TO_STR.TcPOU:1

설명: 2: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 2 <> NULL THEN
       value := 2^;
       // 또는 2.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 2');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(2) THEN
       value := 2.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   2 := ADR(targetVariable);
   IF 2 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 2 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 2^; // NULL 체크 없음!
value := 2.member; // NULL 체크 없음!

✅ 안전: IF 2 <> NULL THEN
value := 2^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(2) THEN
value := 2.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: pAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pAlarm <> NULL THEN
       value := pAlarm^;
       // 또는 pAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pAlarm) THEN
       value := pAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pAlarm := ADR(targetVariable);
   IF pAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pAlarm^; // NULL 체크 없음!
value := pAlarm.member; // NULL 체크 없음!

✅ 안전: IF pAlarm <> NULL THEN
value := pAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pAlarm) THEN
value := pAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: pAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pAlarm <> NULL THEN
       value := pAlarm^;
       // 또는 pAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pAlarm) THEN
       value := pAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pAlarm := ADR(targetVariable);
   IF pAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pAlarm^; // NULL 체크 없음!
value := pAlarm.member; // NULL 체크 없음!

✅ 안전: IF pAlarm <> NULL THEN
value := pAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pAlarm) THEN
value := pAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: eDesc_Alarm_Level: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_Alarm_Level <> NULL THEN
       value := eDesc_Alarm_Level^;
       // 또는 eDesc_Alarm_Level.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_Alarm_Level');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_Alarm_Level) THEN
       value := eDesc_Alarm_Level.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_Alarm_Level := ADR(targetVariable);
   IF eDesc_Alarm_Level = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_Alarm_Level = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_Alarm_Level^; // NULL 체크 없음!
value := eDesc_Alarm_Level.member; // NULL 체크 없음!

✅ 안전: IF eDesc_Alarm_Level <> NULL THEN
value := eDesc_Alarm_Level^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_Alarm_Level) THEN
value := eDesc_Alarm_Level.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: pAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pAlarm <> NULL THEN
       value := pAlarm^;
       // 또는 pAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pAlarm) THEN
       value := pAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pAlarm := ADR(targetVariable);
   IF pAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pAlarm^; // NULL 체크 없음!
value := pAlarm.member; // NULL 체크 없음!

✅ 안전: IF pAlarm <> NULL THEN
value := pAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pAlarm) THEN
value := pAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: SEQ_Function_Process: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF SEQ_Function_Process <> NULL THEN
       value := SEQ_Function_Process^;
       // 또는 SEQ_Function_Process.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: SEQ_Function_Process');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(SEQ_Function_Process) THEN
       value := SEQ_Function_Process.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   SEQ_Function_Process := ADR(targetVariable);
   IF SEQ_Function_Process = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF SEQ_Function_Process = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := SEQ_Function_Process^; // NULL 체크 없음!
value := SEQ_Function_Process.member; // NULL 체크 없음!

✅ 안전: IF SEQ_Function_Process <> NULL THEN
value := SEQ_Function_Process^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(SEQ_Function_Process) THEN
value := SEQ_Function_Process.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: pAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pAlarm <> NULL THEN
       value := pAlarm^;
       // 또는 pAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pAlarm) THEN
       value := pAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pAlarm := ADR(targetVariable);
   IF pAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pAlarm^; // NULL 체크 없음!
value := pAlarm.member; // NULL 체크 없음!

✅ 안전: IF pAlarm <> NULL THEN
value := pAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pAlarm) THEN
value := pAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: pAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pAlarm <> NULL THEN
       value := pAlarm^;
       // 또는 pAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pAlarm) THEN
       value := pAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pAlarm := ADR(targetVariable);
   IF pAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pAlarm^; // NULL 체크 없음!
value := pAlarm.member; // NULL 체크 없음!

✅ 안전: IF pAlarm <> NULL THEN
value := pAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pAlarm) THEN
value := pAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: pAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pAlarm <> NULL THEN
       value := pAlarm^;
       // 또는 pAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pAlarm) THEN
       value := pAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pAlarm := ADR(targetVariable);
   IF pAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pAlarm^; // NULL 체크 없음!
value := pAlarm.member; // NULL 체크 없음!

✅ 안전: IF pAlarm <> NULL THEN
value := pAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pAlarm) THEN
value := pAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: pAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pAlarm <> NULL THEN
       value := pAlarm^;
       // 또는 pAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pAlarm) THEN
       value := pAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pAlarm := ADR(targetVariable);
   IF pAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pAlarm^; // NULL 체크 없음!
value := pAlarm.member; // NULL 체크 없음!

✅ 안전: IF pAlarm <> NULL THEN
value := pAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pAlarm) THEN
value := pAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: pAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pAlarm <> NULL THEN
       value := pAlarm^;
       // 또는 pAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pAlarm) THEN
       value := pAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pAlarm := ADR(targetVariable);
   IF pAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pAlarm^; // NULL 체크 없음!
value := pAlarm.member; // NULL 체크 없음!

✅ 안전: IF pAlarm <> NULL THEN
value := pAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pAlarm) THEN
value := pAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: pAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pAlarm <> NULL THEN
       value := pAlarm^;
       // 또는 pAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pAlarm) THEN
       value := pAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pAlarm := ADR(targetVariable);
   IF pAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pAlarm^; // NULL 체크 없음!
value := pAlarm.member; // NULL 체크 없음!

✅ 안전: IF pAlarm <> NULL THEN
value := pAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pAlarm) THEN
value := pAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: pAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pAlarm <> NULL THEN
       value := pAlarm^;
       // 또는 pAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pAlarm) THEN
       value := pAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pAlarm := ADR(targetVariable);
   IF pAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pAlarm^; // NULL 체크 없음!
value := pAlarm.member; // NULL 체크 없음!

✅ 안전: IF pAlarm <> NULL THEN
value := pAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pAlarm) THEN
value := pAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: eDesc_Alarm_Level: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_Alarm_Level <> NULL THEN
       value := eDesc_Alarm_Level^;
       // 또는 eDesc_Alarm_Level.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_Alarm_Level');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_Alarm_Level) THEN
       value := eDesc_Alarm_Level.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_Alarm_Level := ADR(targetVariable);
   IF eDesc_Alarm_Level = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_Alarm_Level = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_Alarm_Level^; // NULL 체크 없음!
value := eDesc_Alarm_Level.member; // NULL 체크 없음!

✅ 안전: IF eDesc_Alarm_Level <> NULL THEN
value := eDesc_Alarm_Level^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_Alarm_Level) THEN
value := eDesc_Alarm_Level.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: eDesc_Alarm_Level: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_Alarm_Level <> NULL THEN
       value := eDesc_Alarm_Level^;
       // 또는 eDesc_Alarm_Level.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_Alarm_Level');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_Alarm_Level) THEN
       value := eDesc_Alarm_Level.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_Alarm_Level := ADR(targetVariable);
   IF eDesc_Alarm_Level = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_Alarm_Level = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_Alarm_Level^; // NULL 체크 없음!
value := eDesc_Alarm_Level.member; // NULL 체크 없음!

✅ 안전: IF eDesc_Alarm_Level <> NULL THEN
value := eDesc_Alarm_Level^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_Alarm_Level) THEN
value := eDesc_Alarm_Level.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: FB_Alarm: 101줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: FB_Alarm = 101줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: iPost = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iPost - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iPost >= (TRUE - 1.0E-6) AND
      iPost <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iPost >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iPost * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iPost = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iPost - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: DX_INF_State_Process = eProcess_Processing: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Process >= (eProcess_Processing - 1.0E-6) AND
      DX_INF_State_Process <= (eProcess_Processing + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Process >= eProcess_Processing THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Process * 10.0);
   intTarget := REAL_TO_DINT(eProcess_Processing * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Process = eProcess_Processing THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: Pause_State = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Pause_State - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Pause_State >= (FALSE - 1.0E-6) AND
      Pause_State <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Pause_State >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Pause_State * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Pause_State = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Pause_State - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: DX_INF_State_Process = eProcess_Processing: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Process >= (eProcess_Processing - 1.0E-6) AND
      DX_INF_State_Process <= (eProcess_Processing + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Process >= eProcess_Processing THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Process * 10.0);
   intTarget := REAL_TO_DINT(eProcess_Processing * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Process = eProcess_Processing THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: DX_INF_Abort_Run = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_Abort_Run - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_Abort_Run >= (FALSE - 1.0E-6) AND
      DX_INF_Abort_Run <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_Abort_Run >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_Abort_Run * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_Abort_Run = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_Abort_Run - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: DX_INF_State_Process = eProcess_Processing: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Process >= (eProcess_Processing - 1.0E-6) AND
      DX_INF_State_Process <= (eProcess_Processing + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Process >= eProcess_Processing THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Process * 10.0);
   intTarget := REAL_TO_DINT(eProcess_Processing * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Process = eProcess_Processing THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: StepNum = 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(StepNum - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF StepNum >= (0 - 1.0E-6) AND
      StepNum <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF StepNum >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(StepNum * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF StepNum = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(StepNum - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: StepNum = AX_INF_Process_CurrentStep: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(StepNum - AX_INF_Process_CurrentStep) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF StepNum >= (AX_INF_Process_CurrentStep - 1.0E-6) AND
      StepNum <= (AX_INF_Process_CurrentStep + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF StepNum >= AX_INF_Process_CurrentStep THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(StepNum * 10.0);
   intTarget := REAL_TO_DINT(AX_INF_Process_CurrentStep * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF StepNum = AX_INF_Process_CurrentStep THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(StepNum - AX_INF_Process_CurrentStep) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: DX_INF_State_Process = eProcess_Processing: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Process >= (eProcess_Processing - 1.0E-6) AND
      DX_INF_State_Process <= (eProcess_Processing + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Process >= eProcess_Processing THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Process * 10.0);
   intTarget := REAL_TO_DINT(eProcess_Processing * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Process = eProcess_Processing THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: DX_INF_Abort_Run = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_Abort_Run - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_Abort_Run >= (FALSE - 1.0E-6) AND
      DX_INF_Abort_Run <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_Abort_Run >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_Abort_Run * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_Abort_Run = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_Abort_Run - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: DX_INF_State_Module <> eModule_Offline: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Offline) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Offline - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Offline + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Offline THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Offline * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Offline THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Offline) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: iClear = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iClear - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iClear >= (TRUE - 1.0E-6) AND
      iClear <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iClear >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iClear * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iClear = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iClear - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: AlarmUse[iIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iIndex >= 1 AND
      iIndex <= 10 THEN
       value := AlarmUse[iIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iIndex, 10);
   value := AlarmUse[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iIndex >= ARRAY_MIN AND iIndex <= ARRAY_MAX THEN
       value := AlarmUse[iIndex];
   END_IF

예시:

❌ 위험: value := AlarmUse[iIndex]; // 범위 검사 없음!

✅ 안전: IF iIndex >= 1 AND iIndex <= 10 THEN
value := AlarmUse[iIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: ALM[iIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iIndex >= 1 AND
      iIndex <= 10 THEN
       value := ALM[iIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iIndex, 10);
   value := ALM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iIndex >= ARRAY_MIN AND iIndex <= ARRAY_MAX THEN
       value := ALM[iIndex];
   END_IF

예시:

❌ 위험: value := ALM[iIndex]; // 범위 검사 없음!

✅ 안전: IF iIndex >= 1 AND iIndex <= 10 THEN
value := ALM[iIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: pALM[iIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iIndex >= 1 AND
      iIndex <= 10 THEN
       value := pALM[iIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iIndex, 10);
   value := pALM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iIndex >= ARRAY_MIN AND iIndex <= ARRAY_MAX THEN
       value := pALM[iIndex];
   END_IF

예시:

❌ 위험: value := pALM[iIndex]; // 범위 검사 없음!

✅ 안전: IF iIndex >= 1 AND iIndex <= 10 THEN
value := pALM[iIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: Level[iIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iIndex >= 1 AND
      iIndex <= 10 THEN
       value := Level[iIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iIndex, 10);
   value := Level[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iIndex >= ARRAY_MIN AND iIndex <= ARRAY_MAX THEN
       value := Level[iIndex];
   END_IF

예시:

❌ 위험: value := Level[iIndex]; // 범위 검사 없음!

✅ 안전: IF iIndex >= 1 AND iIndex <= 10 THEN
value := Level[iIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: ProcessAction[iIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iIndex >= 1 AND
      iIndex <= 10 THEN
       value := ProcessAction[iIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iIndex, 10);
   value := ProcessAction[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iIndex >= ARRAY_MIN AND iIndex <= ARRAY_MAX THEN
       value := ProcessAction[iIndex];
   END_IF

예시:

❌ 위험: value := ProcessAction[iIndex]; // 범위 검사 없음!

✅ 안전: IF iIndex >= 1 AND iIndex <= 10 THEN
value := ProcessAction[iIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: ProcessAction[iIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iIndex >= 1 AND
      iIndex <= 10 THEN
       value := ProcessAction[iIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iIndex, 10);
   value := ProcessAction[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iIndex >= ARRAY_MIN AND iIndex <= ARRAY_MAX THEN
       value := ProcessAction[iIndex];
   END_IF

예시:

❌ 위험: value := ProcessAction[iIndex]; // 범위 검사 없음!

✅ 안전: IF iIndex >= 1 AND iIndex <= 10 THEN
value := ProcessAction[iIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: ProcessInfor[iIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iIndex >= 1 AND
      iIndex <= 10 THEN
       value := ProcessInfor[iIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iIndex, 10);
   value := ProcessInfor[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iIndex >= ARRAY_MIN AND iIndex <= ARRAY_MAX THEN
       value := ProcessInfor[iIndex];
   END_IF

예시:

❌ 위험: value := ProcessInfor[iIndex]; // 범위 검사 없음!

✅ 안전: IF iIndex >= 1 AND iIndex <= 10 THEN
value := ProcessInfor[iIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: ProcessInfor[iIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iIndex >= 1 AND
      iIndex <= 10 THEN
       value := ProcessInfor[iIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iIndex, 10);
   value := ProcessInfor[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iIndex >= ARRAY_MIN AND iIndex <= ARRAY_MAX THEN
       value := ProcessInfor[iIndex];
   END_IF

예시:

❌ 위험: value := ProcessInfor[iIndex]; // 범위 검사 없음!

✅ 안전: IF iIndex >= 1 AND iIndex <= 10 THEN
value := ProcessInfor[iIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: ProcessAction[iIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iIndex >= 1 AND
      iIndex <= 10 THEN
       value := ProcessAction[iIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iIndex, 10);
   value := ProcessAction[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iIndex >= ARRAY_MIN AND iIndex <= ARRAY_MAX THEN
       value := ProcessAction[iIndex];
   END_IF

예시:

❌ 위험: value := ProcessAction[iIndex]; // 범위 검사 없음!

✅ 안전: IF iIndex >= 1 AND iIndex <= 10 THEN
value := ProcessAction[iIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: ProcessInfor[iIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iIndex >= 1 AND
      iIndex <= 10 THEN
       value := ProcessInfor[iIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iIndex, 10);
   value := ProcessInfor[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iIndex >= ARRAY_MIN AND iIndex <= ARRAY_MAX THEN
       value := ProcessInfor[iIndex];
   END_IF

예시:

❌ 위험: value := ProcessInfor[iIndex]; // 범위 검사 없음!

✅ 안전: IF iIndex >= 1 AND iIndex <= 10 THEN
value := ProcessInfor[iIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: HeaterPower[iIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iIndex >= 1 AND
      iIndex <= 10 THEN
       value := HeaterPower[iIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iIndex, 10);
   value := HeaterPower[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iIndex >= ARRAY_MIN AND iIndex <= ARRAY_MAX THEN
       value := HeaterPower[iIndex];
   END_IF

예시:

❌ 위험: value := HeaterPower[iIndex]; // 범위 검사 없음!

✅ 안전: IF iIndex >= 1 AND iIndex <= 10 THEN
value := HeaterPower[iIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: AO_Heater_SP[Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Zone >= 1 AND
      Zone <= 10 THEN
       value := AO_Heater_SP[Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Zone, 10);
   value := AO_Heater_SP[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Zone >= ARRAY_MIN AND Zone <= ARRAY_MAX THEN
       value := AO_Heater_SP[Zone];
   END_IF

예시:

❌ 위험: value := AO_Heater_SP[Zone]; // 범위 검사 없음!

✅ 안전: IF Zone >= 1 AND Zone <= 10 THEN
value := AO_Heater_SP[Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: AO_Heater_Ramp[Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Zone >= 1 AND
      Zone <= 10 THEN
       value := AO_Heater_Ramp[Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Zone, 10);
   value := AO_Heater_Ramp[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Zone >= ARRAY_MIN AND Zone <= ARRAY_MAX THEN
       value := AO_Heater_Ramp[Zone];
   END_IF

예시:

❌ 위험: value := AO_Heater_Ramp[Zone]; // 범위 검사 없음!

✅ 안전: IF Zone >= 1 AND Zone <= 10 THEN
value := AO_Heater_Ramp[Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: AO_Heater_Power[Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Zone >= 1 AND
      Zone <= 10 THEN
       value := AO_Heater_Power[Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Zone, 10);
   value := AO_Heater_Power[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Zone >= ARRAY_MIN AND Zone <= ARRAY_MAX THEN
       value := AO_Heater_Power[Zone];
   END_IF

예시:

❌ 위험: value := AO_Heater_Power[Zone]; // 범위 검사 없음!

✅ 안전: IF Zone >= 1 AND Zone <= 10 THEN
value := AO_Heater_Power[Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: AO_Heater_Power_Sub[Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Zone >= 1 AND
      Zone <= 10 THEN
       value := AO_Heater_Power_Sub[Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Zone, 10);
   value := AO_Heater_Power_Sub[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Zone >= ARRAY_MIN AND Zone <= ARRAY_MAX THEN
       value := AO_Heater_Power_Sub[Zone];
   END_IF

예시:

❌ 위험: value := AO_Heater_Power_Sub[Zone]; // 범위 검사 없음!

✅ 안전: IF Zone >= 1 AND Zone <= 10 THEN
value := AO_Heater_Power_Sub[Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: HeaterPower[iIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iIndex >= 1 AND
      iIndex <= 10 THEN
       value := HeaterPower[iIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iIndex, 10);
   value := HeaterPower[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iIndex >= ARRAY_MIN AND iIndex <= ARRAY_MAX THEN
       value := HeaterPower[iIndex];
   END_IF

예시:

❌ 위험: value := HeaterPower[iIndex]; // 범위 검사 없음!

✅ 안전: IF iIndex >= 1 AND iIndex <= 10 THEN
value := HeaterPower[iIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: pALM[iIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iIndex >= 1 AND
      iIndex <= 10 THEN
       value := pALM[iIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iIndex, 10);
   value := pALM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iIndex >= ARRAY_MIN AND iIndex <= ARRAY_MAX THEN
       value := pALM[iIndex];
   END_IF

예시:

❌ 위험: value := pALM[iIndex]; // 범위 검사 없음!

✅ 안전: IF iIndex >= 1 AND iIndex <= 10 THEN
value := pALM[iIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: z: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF z <> NULL THEN
       value := z^;
       // 또는 z.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: z');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(z) THEN
       value := z.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   z := ADR(targetVariable);
   IF z = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF z = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := z^; // NULL 체크 없음!
value := z.member; // NULL 체크 없음!

✅ 안전: IF z <> NULL THEN
value := z^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(z) THEN
value := z.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: z: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF z <> NULL THEN
       value := z^;
       // 또는 z.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: z');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(z) THEN
       value := z.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   z := ADR(targetVariable);
   IF z = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF z = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := z^; // NULL 체크 없음!
value := z.member; // NULL 체크 없음!

✅ 안전: IF z <> NULL THEN
value := z^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(z) THEN
value := z.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: z: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF z <> NULL THEN
       value := z^;
       // 또는 z.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: z');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(z) THEN
       value := z.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   z := ADR(targetVariable);
   IF z = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF z = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := z^; // NULL 체크 없음!
value := z.member; // NULL 체크 없음!

✅ 안전: IF z <> NULL THEN
value := z^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(z) THEN
value := z.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: z: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF z <> NULL THEN
       value := z^;
       // 또는 z.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: z');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(z) THEN
       value := z.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   z := ADR(targetVariable);
   IF z = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF z = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := z^; // NULL 체크 없음!
value := z.member; // NULL 체크 없음!

✅ 안전: IF z <> NULL THEN
value := z^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(z) THEN
value := z.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: FB_BasicPID_RSD: 176줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: FB_BasicPID_RSD = 176줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: fCtrlCycleTime <> fCtrlCycleTimeOld: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(fCtrlCycleTime - fCtrlCycleTimeOld) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF fCtrlCycleTime >= (fCtrlCycleTimeOld - 1.0E-6) AND
      fCtrlCycleTime <= (fCtrlCycleTimeOld + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF fCtrlCycleTime >= fCtrlCycleTimeOld THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(fCtrlCycleTime * 10.0);
   intTarget := REAL_TO_DINT(fCtrlCycleTimeOld * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF fCtrlCycleTime = fCtrlCycleTimeOld THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(fCtrlCycleTime - fCtrlCycleTimeOld) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:1

설명: iReset = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iReset - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iReset >= (TRUE - 1.0E-6) AND
      iReset <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iReset >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iReset * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iReset = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iReset - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: 32767: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 32767 <> NULL THEN
       value := 32767^;
       // 또는 32767.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 32767');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(32767) THEN
       value := 32767.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   32767 := ADR(targetVariable);
   IF 32767 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 32767 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 32767^; // NULL 체크 없음!
value := 32767.member; // NULL 체크 없음!

✅ 안전: IF 32767 <> NULL THEN
value := 32767^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(32767) THEN
value := 32767.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: 1: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 1 <> NULL THEN
       value := 1^;
       // 또는 1.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 1');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(1) THEN
       value := 1.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   1 := ADR(targetVariable);
   IF 1 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 1 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 1^; // NULL 체크 없음!
value := 1.member; // NULL 체크 없음!

✅ 안전: IF 1 <> NULL THEN
value := 1^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(1) THEN
value := 1.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: 1000: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 1000 <> NULL THEN
       value := 1000^;
       // 또는 1000.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 1000');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(1000) THEN
       value := 1000.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   1000 := ADR(targetVariable);
   IF 1000 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 1000 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 1000^; // NULL 체크 없음!
value := 1000.member; // NULL 체크 없음!

✅ 안전: IF 1000 <> NULL THEN
value := 1000^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(1000) THEN
value := 1000.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: iParameter: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF iParameter <> NULL THEN
       value := iParameter^;
       // 또는 iParameter.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: iParameter');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(iParameter) THEN
       value := iParameter.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   iParameter := ADR(targetVariable);
   IF iParameter = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF iParameter = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := iParameter^; // NULL 체크 없음!
value := iParameter.member; // NULL 체크 없음!

✅ 안전: IF iParameter <> NULL THEN
value := iParameter^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(iParameter) THEN
value := iParameter.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: 1000: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 1000 <> NULL THEN
       value := 1000^;
       // 또는 1000.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 1000');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(1000) THEN
       value := 1000.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   1000 := ADR(targetVariable);
   IF 1000 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 1000 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 1000^; // NULL 체크 없음!
value := 1000.member; // NULL 체크 없음!

✅ 안전: IF 1000 <> NULL THEN
value := 1000^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(1000) THEN
value := 1000.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: iParameter: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF iParameter <> NULL THEN
       value := iParameter^;
       // 또는 iParameter.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: iParameter');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(iParameter) THEN
       value := iParameter.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   iParameter := ADR(targetVariable);
   IF iParameter = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF iParameter = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := iParameter^; // NULL 체크 없음!
value := iParameter.member; // NULL 체크 없음!

✅ 안전: IF iParameter <> NULL THEN
value := iParameter^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(iParameter) THEN
value := iParameter.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: 1000: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 1000 <> NULL THEN
       value := 1000^;
       // 또는 1000.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 1000');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(1000) THEN
       value := 1000.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   1000 := ADR(targetVariable);
   IF 1000 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 1000 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 1000^; // NULL 체크 없음!
value := 1000.member; // NULL 체크 없음!

✅ 안전: IF 1000 <> NULL THEN
value := 1000^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(1000) THEN
value := 1000.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: iParameter: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF iParameter <> NULL THEN
       value := iParameter^;
       // 또는 iParameter.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: iParameter');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(iParameter) THEN
       value := iParameter.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   iParameter := ADR(targetVariable);
   IF iParameter = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF iParameter = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := iParameter^; // NULL 체크 없음!
value := iParameter.member; // NULL 체크 없음!

✅ 안전: IF iParameter <> NULL THEN
value := iParameter^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(iParameter) THEN
value := iParameter.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: 1000: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 1000 <> NULL THEN
       value := 1000^;
       // 또는 1000.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 1000');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(1000) THEN
       value := 1000.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   1000 := ADR(targetVariable);
   IF 1000 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 1000 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 1000^; // NULL 체크 없음!
value := 1000.member; // NULL 체크 없음!

✅ 안전: IF 1000 <> NULL THEN
value := 1000^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(1000) THEN
value := 1000.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: iParameter: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF iParameter <> NULL THEN
       value := iParameter^;
       // 또는 iParameter.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: iParameter');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(iParameter) THEN
       value := iParameter.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   iParameter := ADR(targetVariable);
   IF iParameter = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF iParameter = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := iParameter^; // NULL 체크 없음!
value := iParameter.member; // NULL 체크 없음!

✅ 안전: IF iParameter <> NULL THEN
value := iParameter^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(iParameter) THEN
value := iParameter.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: 1000: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 1000 <> NULL THEN
       value := 1000^;
       // 또는 1000.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 1000');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(1000) THEN
       value := 1000.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   1000 := ADR(targetVariable);
   IF 1000 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 1000 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 1000^; // NULL 체크 없음!
value := 1000.member; // NULL 체크 없음!

✅ 안전: IF 1000 <> NULL THEN
value := 1000^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(1000) THEN
value := 1000.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: iParameter: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF iParameter <> NULL THEN
       value := iParameter^;
       // 또는 iParameter.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: iParameter');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(iParameter) THEN
       value := iParameter.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   iParameter := ADR(targetVariable);
   IF iParameter = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF iParameter = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := iParameter^; // NULL 체크 없음!
value := iParameter.member; // NULL 체크 없음!

✅ 안전: IF iParameter <> NULL THEN
value := iParameter^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(iParameter) THEN
value := iParameter.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: 1000: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 1000 <> NULL THEN
       value := 1000^;
       // 또는 1000.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 1000');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(1000) THEN
       value := 1000.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   1000 := ADR(targetVariable);
   IF 1000 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 1000 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 1000^; // NULL 체크 없음!
value := 1000.member; // NULL 체크 없음!

✅ 안전: IF 1000 <> NULL THEN
value := 1000^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(1000) THEN
value := 1000.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: iParameter: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF iParameter <> NULL THEN
       value := iParameter^;
       // 또는 iParameter.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: iParameter');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(iParameter) THEN
       value := iParameter.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   iParameter := ADR(targetVariable);
   IF iParameter = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF iParameter = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := iParameter^; // NULL 체크 없음!
value := iParameter.member; // NULL 체크 없음!

✅ 안전: IF iParameter <> NULL THEN
value := iParameter^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(iParameter) THEN
value := iParameter.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: 1000: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 1000 <> NULL THEN
       value := 1000^;
       // 또는 1000.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 1000');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(1000) THEN
       value := 1000.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   1000 := ADR(targetVariable);
   IF 1000 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 1000 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 1000^; // NULL 체크 없음!
value := 1000.member; // NULL 체크 없음!

✅ 안전: IF 1000 <> NULL THEN
value := 1000^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(1000) THEN
value := 1000.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: iParameter: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF iParameter <> NULL THEN
       value := iParameter^;
       // 또는 iParameter.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: iParameter');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(iParameter) THEN
       value := iParameter.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   iParameter := ADR(targetVariable);
   IF iParameter = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF iParameter = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := iParameter^; // NULL 체크 없음!
value := iParameter.member; // NULL 체크 없음!

✅ 안전: IF iParameter <> NULL THEN
value := iParameter^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(iParameter) THEN
value := iParameter.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: 1000: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 1000 <> NULL THEN
       value := 1000^;
       // 또는 1000.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 1000');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(1000) THEN
       value := 1000.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   1000 := ADR(targetVariable);
   IF 1000 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 1000 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 1000^; // NULL 체크 없음!
value := 1000.member; // NULL 체크 없음!

✅ 안전: IF 1000 <> NULL THEN
value := 1000^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(1000) THEN
value := 1000.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: FB_Control_Gas: 479줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: FB_Control_Gas = 479줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: 0 = Parts_Use: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(0 - Parts_Use) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF 0 >= (Parts_Use - 1.0E-6) AND
      0 <= (Parts_Use + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF 0 >= Parts_Use THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(0 * 10.0);
   intTarget := REAL_TO_DINT(Parts_Use * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF 0 = Parts_Use THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(0 - Parts_Use) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: iControlMode = cMFC_SET: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iControlMode - cMFC_SET) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iControlMode >= (cMFC_SET - 1.0E-6) AND
      iControlMode <= (cMFC_SET + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iControlMode >= cMFC_SET THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iControlMode * 10.0);
   intTarget := REAL_TO_DINT(cMFC_SET * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iControlMode = cMFC_SET THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iControlMode - cMFC_SET) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: iAlarmUseCheck = eAlarmUse_Use: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iAlarmUseCheck - eAlarmUse_Use) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iAlarmUseCheck >= (eAlarmUse_Use - 1.0E-6) AND
      iAlarmUseCheck <= (eAlarmUse_Use + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iAlarmUseCheck >= eAlarmUse_Use THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iAlarmUseCheck * 10.0);
   intTarget := REAL_TO_DINT(eAlarmUse_Use * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iAlarmUseCheck = eAlarmUse_Use THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iAlarmUseCheck - eAlarmUse_Use) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: iAlarmUseCheck = eAlarmUse_Use: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iAlarmUseCheck - eAlarmUse_Use) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iAlarmUseCheck >= (eAlarmUse_Use - 1.0E-6) AND
      iAlarmUseCheck <= (eAlarmUse_Use + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iAlarmUseCheck >= eAlarmUse_Use THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iAlarmUseCheck * 10.0);
   intTarget := REAL_TO_DINT(eAlarmUse_Use * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iAlarmUseCheck = eAlarmUse_Use THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iAlarmUseCheck - eAlarmUse_Use) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Pump.TcPOU:1

설명: tDealy: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF tDealy <> NULL THEN
       value := tDealy^;
       // 또는 tDealy.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: tDealy');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(tDealy) THEN
       value := tDealy.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   tDealy := ADR(targetVariable);
   IF tDealy = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF tDealy = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := tDealy^; // NULL 체크 없음!
value := tDealy.member; // NULL 체크 없음!

✅ 안전: IF tDealy <> NULL THEN
value := tDealy^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(tDealy) THEN
value := tDealy.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Pump.TcPOU:1

설명: oldCommand = ePump_NOP: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(oldCommand - ePump_NOP) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF oldCommand >= (ePump_NOP - 1.0E-6) AND
      oldCommand <= (ePump_NOP + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF oldCommand >= ePump_NOP THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(oldCommand * 10.0);
   intTarget := REAL_TO_DINT(ePump_NOP * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF oldCommand = ePump_NOP THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(oldCommand - ePump_NOP) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Pump.TcPOU:1

설명: oldCommand = ePump_Off: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(oldCommand - ePump_Off) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF oldCommand >= (ePump_Off - 1.0E-6) AND
      oldCommand <= (ePump_Off + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF oldCommand >= ePump_Off THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(oldCommand * 10.0);
   intTarget := REAL_TO_DINT(ePump_Off * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF oldCommand = ePump_Off THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(oldCommand - ePump_Off) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Pump.TcPOU:1

설명: oldCommand = ePump_On: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(oldCommand - ePump_On) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF oldCommand >= (ePump_On - 1.0E-6) AND
      oldCommand <= (ePump_On + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF oldCommand >= ePump_On THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(oldCommand * 10.0);
   intTarget := REAL_TO_DINT(ePump_On * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF oldCommand = ePump_On THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(oldCommand - ePump_On) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:1

설명: fbTimer: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbTimer <> NULL THEN
       value := fbTimer^;
       // 또는 fbTimer.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbTimer');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbTimer) THEN
       value := fbTimer.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbTimer := ADR(targetVariable);
   IF fbTimer = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbTimer = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbTimer^; // NULL 체크 없음!
value := fbTimer.member; // NULL 체크 없음!

✅ 안전: IF fbTimer <> NULL THEN
value := fbTimer^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbTimer) THEN
value := fbTimer.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:1

설명: fbTimer: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbTimer <> NULL THEN
       value := fbTimer^;
       // 또는 fbTimer.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbTimer');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbTimer) THEN
       value := fbTimer.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbTimer := ADR(targetVariable);
   IF fbTimer = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbTimer = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbTimer^; // NULL 체크 없음!
value := fbTimer.member; // NULL 체크 없음!

✅ 안전: IF fbTimer <> NULL THEN
value := fbTimer^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbTimer) THEN
value := fbTimer.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:1

설명: Read_RampTime: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Read_RampTime <> NULL THEN
       value := Read_RampTime^;
       // 또는 Read_RampTime.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Read_RampTime');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Read_RampTime) THEN
       value := Read_RampTime.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Read_RampTime := ADR(targetVariable);
   IF Read_RampTime = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Read_RampTime = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Read_RampTime^; // NULL 체크 없음!
value := Read_RampTime.member; // NULL 체크 없음!

✅ 안전: IF Read_RampTime <> NULL THEN
value := Read_RampTime^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Read_RampTime) THEN
value := Read_RampTime.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:1

설명: fbTimer: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbTimer <> NULL THEN
       value := fbTimer^;
       // 또는 fbTimer.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbTimer');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbTimer) THEN
       value := fbTimer.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbTimer := ADR(targetVariable);
   IF fbTimer = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbTimer = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbTimer^; // NULL 체크 없음!
value := fbTimer.member; // NULL 체크 없음!

✅ 안전: IF fbTimer <> NULL THEN
value := fbTimer^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbTimer) THEN
value := fbTimer.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:1

설명: Read_Scale: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Read_Scale <> NULL THEN
       value := Read_Scale^;
       // 또는 Read_Scale.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Read_Scale');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Read_Scale) THEN
       value := Read_Scale.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Read_Scale := ADR(targetVariable);
   IF Read_Scale = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Read_Scale = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Read_Scale^; // NULL 체크 없음!
value := Read_Scale.member; // NULL 체크 없음!

✅ 안전: IF Read_Scale <> NULL THEN
value := Read_Scale^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Read_Scale) THEN
value := Read_Scale.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:1

설명: stParameter_Scale: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF stParameter_Scale <> NULL THEN
       value := stParameter_Scale^;
       // 또는 stParameter_Scale.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: stParameter_Scale');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(stParameter_Scale) THEN
       value := stParameter_Scale.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   stParameter_Scale := ADR(targetVariable);
   IF stParameter_Scale = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF stParameter_Scale = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := stParameter_Scale^; // NULL 체크 없음!
value := stParameter_Scale.member; // NULL 체크 없음!

✅ 안전: IF stParameter_Scale <> NULL THEN
value := stParameter_Scale^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(stParameter_Scale) THEN
value := stParameter_Scale.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:1

설명: stParameter_Scale: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF stParameter_Scale <> NULL THEN
       value := stParameter_Scale^;
       // 또는 stParameter_Scale.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: stParameter_Scale');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(stParameter_Scale) THEN
       value := stParameter_Scale.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   stParameter_Scale := ADR(targetVariable);
   IF stParameter_Scale = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF stParameter_Scale = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := stParameter_Scale^; // NULL 체크 없음!
value := stParameter_Scale.member; // NULL 체크 없음!

✅ 안전: IF stParameter_Scale <> NULL THEN
value := stParameter_Scale^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(stParameter_Scale) THEN
value := stParameter_Scale.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:1

설명: stParameter_Scale: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF stParameter_Scale <> NULL THEN
       value := stParameter_Scale^;
       // 또는 stParameter_Scale.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: stParameter_Scale');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(stParameter_Scale) THEN
       value := stParameter_Scale.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   stParameter_Scale := ADR(targetVariable);
   IF stParameter_Scale = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF stParameter_Scale = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := stParameter_Scale^; // NULL 체크 없음!
value := stParameter_Scale.member; // NULL 체크 없음!

✅ 안전: IF stParameter_Scale <> NULL THEN
value := stParameter_Scale^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(stParameter_Scale) THEN
value := stParameter_Scale.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:1

설명: FB_EXPLICT_MESSAGE: 190줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: FB_EXPLICT_MESSAGE = 190줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:1

설명: in_ui_MFC_Maker = 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(in_ui_MFC_Maker - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF in_ui_MFC_Maker >= (0 - 1.0E-6) AND
      in_ui_MFC_Maker <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF in_ui_MFC_Maker >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(in_ui_MFC_Maker * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF in_ui_MFC_Maker = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(in_ui_MFC_Maker - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:1

설명: in_ui_MFC_Maker = 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(in_ui_MFC_Maker - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF in_ui_MFC_Maker >= (0 - 1.0E-6) AND
      in_ui_MFC_Maker <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF in_ui_MFC_Maker >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(in_ui_MFC_Maker * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF in_ui_MFC_Maker = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(in_ui_MFC_Maker - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Explict_Message_Timer.TcPOU:1

설명: TON_On_Delay: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF TON_On_Delay <> NULL THEN
       value := TON_On_Delay^;
       // 또는 TON_On_Delay.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: TON_On_Delay');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(TON_On_Delay) THEN
       value := TON_On_Delay.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   TON_On_Delay := ADR(targetVariable);
   IF TON_On_Delay = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF TON_On_Delay = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := TON_On_Delay^; // NULL 체크 없음!
value := TON_On_Delay.member; // NULL 체크 없음!

✅ 안전: IF TON_On_Delay <> NULL THEN
value := TON_On_Delay^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(TON_On_Delay) THEN
value := TON_On_Delay.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Explict_Message_Timer.TcPOU:1

설명: TON_Read_Msg: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF TON_Read_Msg <> NULL THEN
       value := TON_Read_Msg^;
       // 또는 TON_Read_Msg.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: TON_Read_Msg');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(TON_Read_Msg) THEN
       value := TON_Read_Msg.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   TON_Read_Msg := ADR(targetVariable);
   IF TON_Read_Msg = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF TON_Read_Msg = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := TON_Read_Msg^; // NULL 체크 없음!
value := TON_Read_Msg.member; // NULL 체크 없음!

✅ 안전: IF TON_Read_Msg <> NULL THEN
value := TON_Read_Msg^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(TON_Read_Msg) THEN
value := TON_Read_Msg.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Heater_Group_Scan.TcPOU:1

설명: Timer: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timer <> NULL THEN
       value := Timer^;
       // 또는 Timer.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timer');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timer) THEN
       value := Timer.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timer := ADR(targetVariable);
   IF Timer = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timer = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timer^; // NULL 체크 없음!
value := Timer.member; // NULL 체크 없음!

✅ 안전: IF Timer <> NULL THEN
value := Timer^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timer) THEN
value := Timer.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Heater_Group_Scan.TcPOU:1

설명: ioAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAlarm <> NULL THEN
       value := ioAlarm^;
       // 또는 ioAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAlarm) THEN
       value := ioAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAlarm := ADR(targetVariable);
   IF ioAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAlarm^; // NULL 체크 없음!
value := ioAlarm.member; // NULL 체크 없음!

✅ 안전: IF ioAlarm <> NULL THEN
value := ioAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAlarm) THEN
value := ioAlarm.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Heater_Group_Scan.TcPOU:1

설명: InValue <> Old_Value: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(InValue - Old_Value) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF InValue >= (Old_Value - 1.0E-6) AND
      InValue <= (Old_Value + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF InValue >= Old_Value THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(InValue * 10.0);
   intTarget := REAL_TO_DINT(Old_Value * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF InValue = Old_Value THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(InValue - Old_Value) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Heater_Group_Scan.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:1

설명: UpdateTimeDeley: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF UpdateTimeDeley <> NULL THEN
       value := UpdateTimeDeley^;
       // 또는 UpdateTimeDeley.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: UpdateTimeDeley');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(UpdateTimeDeley) THEN
       value := UpdateTimeDeley.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   UpdateTimeDeley := ADR(targetVariable);
   IF UpdateTimeDeley = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF UpdateTimeDeley = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := UpdateTimeDeley^; // NULL 체크 없음!
value := UpdateTimeDeley.member; // NULL 체크 없음!

✅ 안전: IF UpdateTimeDeley <> NULL THEN
value := UpdateTimeDeley^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(UpdateTimeDeley) THEN
value := UpdateTimeDeley.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:1

설명: fbEvent: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbEvent <> NULL THEN
       value := fbEvent^;
       // 또는 fbEvent.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbEvent');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbEvent) THEN
       value := fbEvent.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbEvent := ADR(targetVariable);
   IF fbEvent = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbEvent = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbEvent^; // NULL 체크 없음!
value := fbEvent.member; // NULL 체크 없음!

✅ 안전: IF fbEvent <> NULL THEN
value := fbEvent^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbEvent) THEN
value := fbEvent.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:1

설명: fbEcGetAllState: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbEcGetAllState <> NULL THEN
       value := fbEcGetAllState^;
       // 또는 fbEcGetAllState.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbEcGetAllState');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbEcGetAllState) THEN
       value := fbEcGetAllState.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbEcGetAllState := ADR(targetVariable);
   IF fbEcGetAllState = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbEcGetAllState = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbEcGetAllState^; // NULL 체크 없음!
value := fbEcGetAllState.member; // NULL 체크 없음!

✅ 안전: IF fbEcGetAllState <> NULL THEN
value := fbEcGetAllState^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbEcGetAllState) THEN
value := fbEcGetAllState.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:1

설명: fbEcGetAllState: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbEcGetAllState <> NULL THEN
       value := fbEcGetAllState^;
       // 또는 fbEcGetAllState.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbEcGetAllState');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbEcGetAllState) THEN
       value := fbEcGetAllState.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbEcGetAllState := ADR(targetVariable);
   IF fbEcGetAllState = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbEcGetAllState = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbEcGetAllState^; // NULL 체크 없음!
value := fbEcGetAllState.member; // NULL 체크 없음!

✅ 안전: IF fbEcGetAllState <> NULL THEN
value := fbEcGetAllState^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbEcGetAllState) THEN
value := fbEcGetAllState.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:1

설명: trgValue = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(trgValue - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF trgValue >= (TRUE - 1.0E-6) AND
      trgValue <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF trgValue >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(trgValue * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF trgValue = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(trgValue - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:1

설명: ARRAY[0..cMAX_SLAVES]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 0..cMAX_SLAVES >= 1 AND
      0..cMAX_SLAVES <= 10 THEN
       value := ARRAY[0..cMAX_SLAVES];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 0..cMAX_SLAVES, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 0..cMAX_SLAVES >= ARRAY_MIN AND 0..cMAX_SLAVES <= ARRAY_MAX THEN
       value := ARRAY[0..cMAX_SLAVES];
   END_IF

예시:

❌ 위험: value := ARRAY[0..cMAX_SLAVES]; // 범위 검사 없음!

✅ 안전: IF 0..cMAX_SLAVES >= 1 AND 0..cMAX_SLAVES <= 10 THEN
value := ARRAY[0..cMAX_SLAVES];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:1

설명: ARRAY[0..cMAX_SLAVES]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 0..cMAX_SLAVES >= 1 AND
      0..cMAX_SLAVES <= 10 THEN
       value := ARRAY[0..cMAX_SLAVES];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 0..cMAX_SLAVES, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 0..cMAX_SLAVES >= ARRAY_MIN AND 0..cMAX_SLAVES <= ARRAY_MAX THEN
       value := ARRAY[0..cMAX_SLAVES];
   END_IF

예시:

❌ 위험: value := ARRAY[0..cMAX_SLAVES]; // 범위 검사 없음!

✅ 안전: IF 0..cMAX_SLAVES >= 1 AND 0..cMAX_SLAVES <= 10 THEN
value := ARRAY[0..cMAX_SLAVES];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:1

설명: ARRAY[0..200]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 0..200 >= 1 AND
      0..200 <= 10 THEN
       value := ARRAY[0..200];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 0..200, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 0..200 >= ARRAY_MIN AND 0..200 <= ARRAY_MAX THEN
       value := ARRAY[0..200];
   END_IF

예시:

❌ 위험: value := ARRAY[0..200]; // 범위 검사 없음!

✅ 안전: IF 0..200 >= 1 AND 0..200 <= 10 THEN
value := ARRAY[0..200];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:1

설명: DeviceState[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DeviceState[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DeviceState[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DeviceState[i];
   END_IF

예시:

❌ 위험: value := DeviceState[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DeviceState[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:1

설명: arrEcState[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := arrEcState[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := arrEcState[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := arrEcState[i];
   END_IF

예시:

❌ 위험: value := arrEcState[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := arrEcState[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:1

설명: LinkState[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := LinkState[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := LinkState[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := LinkState[i];
   END_IF

예시:

❌ 위험: value := LinkState[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := LinkState[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:1

설명: arrEcState[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := arrEcState[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := arrEcState[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := arrEcState[i];
   END_IF

예시:

❌ 위험: value := arrEcState[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := arrEcState[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal.TcPOU:1

설명: Delay: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Delay <> NULL THEN
       value := Delay^;
       // 또는 Delay.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Delay');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Delay) THEN
       value := Delay.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Delay := ADR(targetVariable);
   IF Delay = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Delay = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Delay^; // NULL 체크 없음!
value := Delay.member; // NULL 체크 없음!

✅ 안전: IF Delay <> NULL THEN
value := Delay^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Delay) THEN
value := Delay.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal.TcPOU:1

설명: ioAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAlarm <> NULL THEN
       value := ioAlarm^;
       // 또는 ioAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAlarm) THEN
       value := ioAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAlarm := ADR(targetVariable);
   IF ioAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAlarm^; // NULL 체크 없음!
value := ioAlarm.member; // NULL 체크 없음!

✅ 안전: IF ioAlarm <> NULL THEN
value := ioAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAlarm) THEN
value := ioAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal.TcPOU:1

설명: ioAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAlarm <> NULL THEN
       value := ioAlarm^;
       // 또는 ioAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAlarm) THEN
       value := ioAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAlarm := ADR(targetVariable);
   IF ioAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAlarm^; // NULL 체크 없음!
value := ioAlarm.member; // NULL 체크 없음!

✅ 안전: IF ioAlarm <> NULL THEN
value := ioAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAlarm) THEN
value := ioAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal.TcPOU:1

설명: ioAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAlarm <> NULL THEN
       value := ioAlarm^;
       // 또는 ioAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAlarm) THEN
       value := ioAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAlarm := ADR(targetVariable);
   IF ioAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAlarm^; // NULL 체크 없음!
value := ioAlarm.member; // NULL 체크 없음!

✅ 안전: IF ioAlarm <> NULL THEN
value := ioAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAlarm) THEN
value := ioAlarm.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal.TcPOU:1

설명: iValue = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iValue - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iValue >= (TRUE - 1.0E-6) AND
      iValue <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iValue >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iValue * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iValue = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iValue - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_BurnBox.TcPOU:1

설명: Delay: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Delay <> NULL THEN
       value := Delay^;
       // 또는 Delay.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Delay');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Delay) THEN
       value := Delay.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Delay := ADR(targetVariable);
   IF Delay = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Delay = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Delay^; // NULL 체크 없음!
value := Delay.member; // NULL 체크 없음!

✅ 안전: IF Delay <> NULL THEN
value := Delay^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Delay) THEN
value := Delay.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_BurnBox.TcPOU:1

설명: ioAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAlarm <> NULL THEN
       value := ioAlarm^;
       // 또는 ioAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAlarm) THEN
       value := ioAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAlarm := ADR(targetVariable);
   IF ioAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAlarm^; // NULL 체크 없음!
value := ioAlarm.member; // NULL 체크 없음!

✅ 안전: IF ioAlarm <> NULL THEN
value := ioAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAlarm) THEN
value := ioAlarm.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_BurnBox.TcPOU:1

설명: iValue = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iValue - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iValue >= (TRUE - 1.0E-6) AND
      iValue <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iValue >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iValue * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iValue = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iValue - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_BurnBox.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_Temp.TcPOU:1

설명: Delay: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Delay <> NULL THEN
       value := Delay^;
       // 또는 Delay.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Delay');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Delay) THEN
       value := Delay.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Delay := ADR(targetVariable);
   IF Delay = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Delay = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Delay^; // NULL 체크 없음!
value := Delay.member; // NULL 체크 없음!

✅ 안전: IF Delay <> NULL THEN
value := Delay^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Delay) THEN
value := Delay.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_Temp.TcPOU:1

설명: ioAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAlarm <> NULL THEN
       value := ioAlarm^;
       // 또는 ioAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAlarm) THEN
       value := ioAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAlarm := ADR(targetVariable);
   IF ioAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAlarm^; // NULL 체크 없음!
value := ioAlarm.member; // NULL 체크 없음!

✅ 안전: IF ioAlarm <> NULL THEN
value := ioAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAlarm) THEN
value := ioAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_Temp.TcPOU:1

설명: ioAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAlarm <> NULL THEN
       value := ioAlarm^;
       // 또는 ioAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAlarm) THEN
       value := ioAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAlarm := ADR(targetVariable);
   IF ioAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAlarm^; // NULL 체크 없음!
value := ioAlarm.member; // NULL 체크 없음!

✅ 안전: IF ioAlarm <> NULL THEN
value := ioAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAlarm) THEN
value := ioAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_Temp.TcPOU:1

설명: ioAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAlarm <> NULL THEN
       value := ioAlarm^;
       // 또는 ioAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAlarm) THEN
       value := ioAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAlarm := ADR(targetVariable);
   IF ioAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAlarm^; // NULL 체크 없음!
value := ioAlarm.member; // NULL 체크 없음!

✅ 안전: IF ioAlarm <> NULL THEN
value := ioAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAlarm) THEN
value := ioAlarm.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_Temp.TcPOU:1

설명: iValue = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iValue - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iValue >= (TRUE - 1.0E-6) AND
      iValue <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iValue >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iValue * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iValue = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iValue - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_Temp.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_TempDelay.TcPOU:1

설명: Timer: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timer <> NULL THEN
       value := Timer^;
       // 또는 Timer.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timer');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timer) THEN
       value := Timer.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timer := ADR(targetVariable);
   IF Timer = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timer = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timer^; // NULL 체크 없음!
value := Timer.member; // NULL 체크 없음!

✅ 안전: IF Timer <> NULL THEN
value := Timer^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timer) THEN
value := Timer.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_TempDelay.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: iType = eInterlock_Value_01_NormalClose: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iType - eInterlock_Value_01_NormalClose) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iType >= (eInterlock_Value_01_NormalClose - 1.0E-6) AND
      iType <= (eInterlock_Value_01_NormalClose + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iType >= eInterlock_Value_01_NormalClose THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iType * 10.0);
   intTarget := REAL_TO_DINT(eInterlock_Value_01_NormalClose * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iType = eInterlock_Value_01_NormalClose THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iType - eInterlock_Value_01_NormalClose) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: iBypass = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iBypass - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iBypass >= (TRUE - 1.0E-6) AND
      iBypass <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iBypass >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iBypass * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iBypass = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iBypass - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: iType = eInterlock_Value_02_NormalOpen: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iType - eInterlock_Value_02_NormalOpen) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iType >= (eInterlock_Value_02_NormalOpen - 1.0E-6) AND
      iType <= (eInterlock_Value_02_NormalOpen + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iType >= eInterlock_Value_02_NormalOpen THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iType * 10.0);
   intTarget := REAL_TO_DINT(eInterlock_Value_02_NormalOpen * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iType = eInterlock_Value_02_NormalOpen THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iType - eInterlock_Value_02_NormalOpen) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: iBypass = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iBypass - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iBypass >= (TRUE - 1.0E-6) AND
      iBypass <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iBypass >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iBypass * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iBypass = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iBypass - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: iType = eInterlock_Value_03_2Way: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iType - eInterlock_Value_03_2Way) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iType >= (eInterlock_Value_03_2Way - 1.0E-6) AND
      iType <= (eInterlock_Value_03_2Way + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iType >= eInterlock_Value_03_2Way THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iType * 10.0);
   intTarget := REAL_TO_DINT(eInterlock_Value_03_2Way * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iType = eInterlock_Value_03_2Way THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iType - eInterlock_Value_03_2Way) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: iBypass = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iBypass - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iBypass >= (TRUE - 1.0E-6) AND
      iBypass <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iBypass >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iBypass * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iBypass = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iBypass - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: iValve = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iValve - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iValve >= (TRUE - 1.0E-6) AND
      iValve <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iValve >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iValve * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iValve = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iValve - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: iCondition <> TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iCondition - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iCondition >= (TRUE - 1.0E-6) AND
      iCondition <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iCondition >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iCondition * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iCondition = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iCondition - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: iValve = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iValve - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iValve >= (FALSE - 1.0E-6) AND
      iValve <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iValve >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iValve * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iValve = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iValve - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: iCondition <> TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iCondition - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iCondition >= (TRUE - 1.0E-6) AND
      iCondition <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iCondition >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iCondition * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iCondition = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iCondition - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: iValve = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iValve - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iValve >= (TRUE - 1.0E-6) AND
      iValve <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iValve >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iValve * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iValve = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iValve - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: iCondition <> TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iCondition - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iCondition >= (TRUE - 1.0E-6) AND
      iCondition <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iCondition >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iCondition * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iCondition = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iCondition - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: fbAlarm[iAlarm]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iAlarm >= 1 AND
      iAlarm <= 10 THEN
       value := fbAlarm[iAlarm];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iAlarm, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iAlarm >= ARRAY_MIN AND iAlarm <= ARRAY_MAX THEN
       value := fbAlarm[iAlarm];
   END_IF

예시:

❌ 위험: value := fbAlarm[iAlarm]; // 범위 검사 없음!

✅ 안전: IF iAlarm >= 1 AND iAlarm <= 10 THEN
value := fbAlarm[iAlarm];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: fbAlarm[iAlarm]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iAlarm >= 1 AND
      iAlarm <= 10 THEN
       value := fbAlarm[iAlarm];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iAlarm, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iAlarm >= ARRAY_MIN AND iAlarm <= ARRAY_MAX THEN
       value := fbAlarm[iAlarm];
   END_IF

예시:

❌ 위험: value := fbAlarm[iAlarm]; // 범위 검사 없음!

✅ 안전: IF iAlarm >= 1 AND iAlarm <= 10 THEN
value := fbAlarm[iAlarm];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: fbAlarm[iAlarm]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iAlarm >= 1 AND
      iAlarm <= 10 THEN
       value := fbAlarm[iAlarm];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iAlarm, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iAlarm >= ARRAY_MIN AND iAlarm <= ARRAY_MAX THEN
       value := fbAlarm[iAlarm];
   END_IF

예시:

❌ 위험: value := fbAlarm[iAlarm]; // 범위 검사 없음!

✅ 안전: IF iAlarm >= 1 AND iAlarm <= 10 THEN
value := fbAlarm[iAlarm];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:1

설명: 2: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 2 <> NULL THEN
       value := 2^;
       // 또는 2.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 2');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(2) THEN
       value := 2.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   2 := ADR(targetVariable);
   IF 2 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 2 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 2^; // NULL 체크 없음!
value := 2.member; // NULL 체크 없음!

✅ 안전: IF 2 <> NULL THEN
value := 2^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(2) THEN
value := 2.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:1

설명: FB_Sdo_Gas: 805줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: FB_Sdo_Gas = 805줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:1

설명: ARRAY[1..cMAX_G_LIFE_Para]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_G_LIFE_Para >= 1 AND
      1..cMAX_G_LIFE_Para <= 10 THEN
       value := ARRAY[1..cMAX_G_LIFE_Para];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_G_LIFE_Para, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_G_LIFE_Para >= ARRAY_MIN AND 1..cMAX_G_LIFE_Para <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_G_LIFE_Para];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_G_LIFE_Para]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_G_LIFE_Para >= 1 AND 1..cMAX_G_LIFE_Para <= 10 THEN
value := ARRAY[1..cMAX_G_LIFE_Para];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:1

설명: ARRAY[1..cMAX_G_LIFE_Para]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_G_LIFE_Para >= 1 AND
      1..cMAX_G_LIFE_Para <= 10 THEN
       value := ARRAY[1..cMAX_G_LIFE_Para];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_G_LIFE_Para, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_G_LIFE_Para >= ARRAY_MIN AND 1..cMAX_G_LIFE_Para <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_G_LIFE_Para];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_G_LIFE_Para]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_G_LIFE_Para >= 1 AND 1..cMAX_G_LIFE_Para <= 10 THEN
value := ARRAY[1..cMAX_G_LIFE_Para];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas_PartsPara.TcPOU:1

설명: FB_Sdo_Gas_PartsPara: 417줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: FB_Sdo_Gas_PartsPara = 417줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Signal_2BYTE.TcPOU:1

설명: Buffer_Data: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Buffer_Data <> NULL THEN
       value := Buffer_Data^;
       // 또는 Buffer_Data.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Buffer_Data');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Buffer_Data) THEN
       value := Buffer_Data.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Buffer_Data := ADR(targetVariable);
   IF Buffer_Data = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Buffer_Data = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Buffer_Data^; // NULL 체크 없음!
value := Buffer_Data.member; // NULL 체크 없음!

✅ 안전: IF Buffer_Data <> NULL THEN
value := Buffer_Data^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Buffer_Data) THEN
value := Buffer_Data.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Signal_2BYTE.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Signal_2BYTE.TcPOU:1

설명: ARRAY[0..15]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 0..15 >= 1 AND
      0..15 <= 10 THEN
       value := ARRAY[0..15];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 0..15, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 0..15 >= ARRAY_MIN AND 0..15 <= ARRAY_MAX THEN
       value := ARRAY[0..15];
   END_IF

예시:

❌ 위험: value := ARRAY[0..15]; // 범위 검사 없음!

✅ 안전: IF 0..15 >= 1 AND 0..15 <= 10 THEN
value := ARRAY[0..15];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Signal_2BYTE.TcPOU:1

설명: aDelay[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := aDelay[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := aDelay[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := aDelay[i];
   END_IF

예시:

❌ 위험: value := aDelay[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := aDelay[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Signal_2BYTE.TcPOU:1

설명: aDelay[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := aDelay[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := aDelay[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := aDelay[i];
   END_IF

예시:

❌ 위험: value := aDelay[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := aDelay[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Signal_2BYTE.TcPOU:1

설명: fbAlarm[iStartAlarm_Number + i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iStartAlarm_Number + i >= 1 AND
      iStartAlarm_Number + i <= 10 THEN
       value := fbAlarm[iStartAlarm_Number + i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iStartAlarm_Number + i, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iStartAlarm_Number + i >= ARRAY_MIN AND iStartAlarm_Number + i <= ARRAY_MAX THEN
       value := fbAlarm[iStartAlarm_Number + i];
   END_IF

예시:

❌ 위험: value := fbAlarm[iStartAlarm_Number + i]; // 범위 검사 없음!

✅ 안전: IF iStartAlarm_Number + i >= 1 AND iStartAlarm_Number + i <= 10 THEN
value := fbAlarm[iStartAlarm_Number + i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:1

설명: Temp_DEV_Time: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Temp_DEV_Time <> NULL THEN
       value := Temp_DEV_Time^;
       // 또는 Temp_DEV_Time.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Temp_DEV_Time');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Temp_DEV_Time) THEN
       value := Temp_DEV_Time.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Temp_DEV_Time := ADR(targetVariable);
   IF Temp_DEV_Time = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Temp_DEV_Time = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Temp_DEV_Time^; // NULL 체크 없음!
value := Temp_DEV_Time.member; // NULL 체크 없음!

✅ 안전: IF Temp_DEV_Time <> NULL THEN
value := Temp_DEV_Time^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Temp_DEV_Time) THEN
value := Temp_DEV_Time.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:1

설명: ioTemp_DEV_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioTemp_DEV_Alarm <> NULL THEN
       value := ioTemp_DEV_Alarm^;
       // 또는 ioTemp_DEV_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioTemp_DEV_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioTemp_DEV_Alarm) THEN
       value := ioTemp_DEV_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioTemp_DEV_Alarm := ADR(targetVariable);
   IF ioTemp_DEV_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioTemp_DEV_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioTemp_DEV_Alarm^; // NULL 체크 없음!
value := ioTemp_DEV_Alarm.member; // NULL 체크 없음!

✅ 안전: IF ioTemp_DEV_Alarm <> NULL THEN
value := ioTemp_DEV_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioTemp_DEV_Alarm) THEN
value := ioTemp_DEV_Alarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:1

설명: Short_S_DEV_Time: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Short_S_DEV_Time <> NULL THEN
       value := Short_S_DEV_Time^;
       // 또는 Short_S_DEV_Time.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Short_S_DEV_Time');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Short_S_DEV_Time) THEN
       value := Short_S_DEV_Time.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Short_S_DEV_Time := ADR(targetVariable);
   IF Short_S_DEV_Time = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Short_S_DEV_Time = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Short_S_DEV_Time^; // NULL 체크 없음!
value := Short_S_DEV_Time.member; // NULL 체크 없음!

✅ 안전: IF Short_S_DEV_Time <> NULL THEN
value := Short_S_DEV_Time^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Short_S_DEV_Time) THEN
value := Short_S_DEV_Time.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:1

설명: ioShort_S_DEV_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioShort_S_DEV_Alarm <> NULL THEN
       value := ioShort_S_DEV_Alarm^;
       // 또는 ioShort_S_DEV_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioShort_S_DEV_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioShort_S_DEV_Alarm) THEN
       value := ioShort_S_DEV_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioShort_S_DEV_Alarm := ADR(targetVariable);
   IF ioShort_S_DEV_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioShort_S_DEV_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioShort_S_DEV_Alarm^; // NULL 체크 없음!
value := ioShort_S_DEV_Alarm.member; // NULL 체크 없음!

✅ 안전: IF ioShort_S_DEV_Alarm <> NULL THEN
value := ioShort_S_DEV_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioShort_S_DEV_Alarm) THEN
value := ioShort_S_DEV_Alarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:1

설명: Short_P_DEV_Time: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Short_P_DEV_Time <> NULL THEN
       value := Short_P_DEV_Time^;
       // 또는 Short_P_DEV_Time.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Short_P_DEV_Time');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Short_P_DEV_Time) THEN
       value := Short_P_DEV_Time.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Short_P_DEV_Time := ADR(targetVariable);
   IF Short_P_DEV_Time = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Short_P_DEV_Time = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Short_P_DEV_Time^; // NULL 체크 없음!
value := Short_P_DEV_Time.member; // NULL 체크 없음!

✅ 안전: IF Short_P_DEV_Time <> NULL THEN
value := Short_P_DEV_Time^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Short_P_DEV_Time) THEN
value := Short_P_DEV_Time.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:1

설명: ioShort_P_DEV_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioShort_P_DEV_Alarm <> NULL THEN
       value := ioShort_P_DEV_Alarm^;
       // 또는 ioShort_P_DEV_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioShort_P_DEV_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioShort_P_DEV_Alarm) THEN
       value := ioShort_P_DEV_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioShort_P_DEV_Alarm := ADR(targetVariable);
   IF ioShort_P_DEV_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioShort_P_DEV_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioShort_P_DEV_Alarm^; // NULL 체크 없음!
value := ioShort_P_DEV_Alarm.member; // NULL 체크 없음!

✅ 안전: IF ioShort_P_DEV_Alarm <> NULL THEN
value := ioShort_P_DEV_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioShort_P_DEV_Alarm) THEN
value := ioShort_P_DEV_Alarm.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:1

설명: TempMode = eHeaterMode_Spike: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TempMode - eHeaterMode_Spike) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TempMode >= (eHeaterMode_Spike - 1.0E-6) AND
      TempMode <= (eHeaterMode_Spike + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TempMode >= eHeaterMode_Spike THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TempMode * 10.0);
   intTarget := REAL_TO_DINT(eHeaterMode_Spike * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TempMode = eHeaterMode_Spike THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TempMode - eHeaterMode_Spike) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:1

설명: S_DEV_Time: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF S_DEV_Time <> NULL THEN
       value := S_DEV_Time^;
       // 또는 S_DEV_Time.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: S_DEV_Time');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(S_DEV_Time) THEN
       value := S_DEV_Time.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   S_DEV_Time := ADR(targetVariable);
   IF S_DEV_Time = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF S_DEV_Time = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := S_DEV_Time^; // NULL 체크 없음!
value := S_DEV_Time.member; // NULL 체크 없음!

✅ 안전: IF S_DEV_Time <> NULL THEN
value := S_DEV_Time^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(S_DEV_Time) THEN
value := S_DEV_Time.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:1

설명: io_S_DEV_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF io_S_DEV_Alarm <> NULL THEN
       value := io_S_DEV_Alarm^;
       // 또는 io_S_DEV_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: io_S_DEV_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(io_S_DEV_Alarm) THEN
       value := io_S_DEV_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   io_S_DEV_Alarm := ADR(targetVariable);
   IF io_S_DEV_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF io_S_DEV_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := io_S_DEV_Alarm^; // NULL 체크 없음!
value := io_S_DEV_Alarm.member; // NULL 체크 없음!

✅ 안전: IF io_S_DEV_Alarm <> NULL THEN
value := io_S_DEV_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(io_S_DEV_Alarm) THEN
value := io_S_DEV_Alarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:1

설명: P_DEV_Time: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF P_DEV_Time <> NULL THEN
       value := P_DEV_Time^;
       // 또는 P_DEV_Time.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: P_DEV_Time');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(P_DEV_Time) THEN
       value := P_DEV_Time.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   P_DEV_Time := ADR(targetVariable);
   IF P_DEV_Time = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF P_DEV_Time = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := P_DEV_Time^; // NULL 체크 없음!
value := P_DEV_Time.member; // NULL 체크 없음!

✅ 안전: IF P_DEV_Time <> NULL THEN
value := P_DEV_Time^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(P_DEV_Time) THEN
value := P_DEV_Time.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:1

설명: io_P_DEV_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF io_P_DEV_Alarm <> NULL THEN
       value := io_P_DEV_Alarm^;
       // 또는 io_P_DEV_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: io_P_DEV_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(io_P_DEV_Alarm) THEN
       value := io_P_DEV_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   io_P_DEV_Alarm := ADR(targetVariable);
   IF io_P_DEV_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF io_P_DEV_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := io_P_DEV_Alarm^; // NULL 체크 없음!
value := io_P_DEV_Alarm.member; // NULL 체크 없음!

✅ 안전: IF io_P_DEV_Alarm <> NULL THEN
value := io_P_DEV_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(io_P_DEV_Alarm) THEN
value := io_P_DEV_Alarm.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:1

설명: TempMode = eHeaterMode_Spike: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TempMode - eHeaterMode_Spike) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TempMode >= (eHeaterMode_Spike - 1.0E-6) AND
      TempMode <= (eHeaterMode_Spike + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TempMode >= eHeaterMode_Spike THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TempMode * 10.0);
   intTarget := REAL_TO_DINT(eHeaterMode_Spike * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TempMode = eHeaterMode_Spike THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TempMode - eHeaterMode_Spike) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:1

설명: DEV_Time: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF DEV_Time <> NULL THEN
       value := DEV_Time^;
       // 또는 DEV_Time.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: DEV_Time');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(DEV_Time) THEN
       value := DEV_Time.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   DEV_Time := ADR(targetVariable);
   IF DEV_Time = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF DEV_Time = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := DEV_Time^; // NULL 체크 없음!
value := DEV_Time.member; // NULL 체크 없음!

✅ 안전: IF DEV_Time <> NULL THEN
value := DEV_Time^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(DEV_Time) THEN
value := DEV_Time.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:1

설명: io_DEV_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF io_DEV_Alarm <> NULL THEN
       value := io_DEV_Alarm^;
       // 또는 io_DEV_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: io_DEV_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(io_DEV_Alarm) THEN
       value := io_DEV_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   io_DEV_Alarm := ADR(targetVariable);
   IF io_DEV_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF io_DEV_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := io_DEV_Alarm^; // NULL 체크 없음!
value := io_DEV_Alarm.member; // NULL 체크 없음!

✅ 안전: IF io_DEV_Alarm <> NULL THEN
value := io_DEV_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(io_DEV_Alarm) THEN
value := io_DEV_Alarm.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:1

설명: Old_TempMode_1 <> TempMode_1: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Old_TempMode_1 - TempMode_1) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Old_TempMode_1 >= (TempMode_1 - 1.0E-6) AND
      Old_TempMode_1 <= (TempMode_1 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Old_TempMode_1 >= TempMode_1 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Old_TempMode_1 * 10.0);
   intTarget := REAL_TO_DINT(TempMode_1 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Old_TempMode_1 = TempMode_1 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Old_TempMode_1 - TempMode_1) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:1

설명: Old_TempMode_2 <> TempMode_2: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Old_TempMode_2 - TempMode_2) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Old_TempMode_2 >= (TempMode_2 - 1.0E-6) AND
      Old_TempMode_2 <= (TempMode_2 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Old_TempMode_2 >= TempMode_2 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Old_TempMode_2 * 10.0);
   intTarget := REAL_TO_DINT(TempMode_2 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Old_TempMode_2 = TempMode_2 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Old_TempMode_2 - TempMode_2) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:1

설명: TempMode_1 = eHeaterMode_Spike: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TempMode_1 - eHeaterMode_Spike) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TempMode_1 >= (eHeaterMode_Spike - 1.0E-6) AND
      TempMode_1 <= (eHeaterMode_Spike + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TempMode_1 >= eHeaterMode_Spike THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TempMode_1 * 10.0);
   intTarget := REAL_TO_DINT(eHeaterMode_Spike * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TempMode_1 = eHeaterMode_Spike THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TempMode_1 - eHeaterMode_Spike) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:1

설명: TempMode_2 = eHeaterMode_Spike: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TempMode_2 - eHeaterMode_Spike) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TempMode_2 >= (eHeaterMode_Spike - 1.0E-6) AND
      TempMode_2 <= (eHeaterMode_Spike + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TempMode_2 >= eHeaterMode_Spike THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TempMode_2 * 10.0);
   intTarget := REAL_TO_DINT(eHeaterMode_Spike * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TempMode_2 = eHeaterMode_Spike THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TempMode_2 - eHeaterMode_Spike) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: tTimeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF tTimeout <> NULL THEN
       value := tTimeout^;
       // 또는 tTimeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: tTimeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(tTimeout) THEN
       value := tTimeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   tTimeout := ADR(targetVariable);
   IF tTimeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF tTimeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := tTimeout^; // NULL 체크 없음!
value := tTimeout.member; // NULL 체크 없음!

✅ 안전: IF tTimeout <> NULL THEN
value := tTimeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(tTimeout) THEN
value := tTimeout.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: fbSdoReadData: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbSdoReadData <> NULL THEN
       value := fbSdoReadData^;
       // 또는 fbSdoReadData.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbSdoReadData');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbSdoReadData) THEN
       value := fbSdoReadData.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbSdoReadData := ADR(targetVariable);
   IF fbSdoReadData = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbSdoReadData = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbSdoReadData^; // NULL 체크 없음!
value := fbSdoReadData.member; // NULL 체크 없음!

✅ 안전: IF fbSdoReadData <> NULL THEN
value := fbSdoReadData^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbSdoReadData) THEN
value := fbSdoReadData.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: fbSdoReadData: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbSdoReadData <> NULL THEN
       value := fbSdoReadData^;
       // 또는 fbSdoReadData.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbSdoReadData');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbSdoReadData) THEN
       value := fbSdoReadData.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbSdoReadData := ADR(targetVariable);
   IF fbSdoReadData = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbSdoReadData = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbSdoReadData^; // NULL 체크 없음!
value := fbSdoReadData.member; // NULL 체크 없음!

✅ 안전: IF fbSdoReadData <> NULL THEN
value := fbSdoReadData^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbSdoReadData) THEN
value := fbSdoReadData.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: fbSdoReadData: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbSdoReadData <> NULL THEN
       value := fbSdoReadData^;
       // 또는 fbSdoReadData.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbSdoReadData');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbSdoReadData) THEN
       value := fbSdoReadData.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbSdoReadData := ADR(targetVariable);
   IF fbSdoReadData = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbSdoReadData = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbSdoReadData^; // NULL 체크 없음!
value := fbSdoReadData.member; // NULL 체크 없음!

✅ 안전: IF fbSdoReadData <> NULL THEN
value := fbSdoReadData^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbSdoReadData) THEN
value := fbSdoReadData.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: fbSdoReadData: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbSdoReadData <> NULL THEN
       value := fbSdoReadData^;
       // 또는 fbSdoReadData.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbSdoReadData');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbSdoReadData) THEN
       value := fbSdoReadData.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbSdoReadData := ADR(targetVariable);
   IF fbSdoReadData = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbSdoReadData = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbSdoReadData^; // NULL 체크 없음!
value := fbSdoReadData.member; // NULL 체크 없음!

✅ 안전: IF fbSdoReadData <> NULL THEN
value := fbSdoReadData^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbSdoReadData) THEN
value := fbSdoReadData.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: fbSdoReadData: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbSdoReadData <> NULL THEN
       value := fbSdoReadData^;
       // 또는 fbSdoReadData.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbSdoReadData');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbSdoReadData) THEN
       value := fbSdoReadData.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbSdoReadData := ADR(targetVariable);
   IF fbSdoReadData = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbSdoReadData = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbSdoReadData^; // NULL 체크 없음!
value := fbSdoReadData.member; // NULL 체크 없음!

✅ 안전: IF fbSdoReadData <> NULL THEN
value := fbSdoReadData^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbSdoReadData) THEN
value := fbSdoReadData.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: fbSdoReadData: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbSdoReadData <> NULL THEN
       value := fbSdoReadData^;
       // 또는 fbSdoReadData.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbSdoReadData');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbSdoReadData) THEN
       value := fbSdoReadData.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbSdoReadData := ADR(targetVariable);
   IF fbSdoReadData = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbSdoReadData = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbSdoReadData^; // NULL 체크 없음!
value := fbSdoReadData.member; // NULL 체크 없음!

✅ 안전: IF fbSdoReadData <> NULL THEN
value := fbSdoReadData^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbSdoReadData) THEN
value := fbSdoReadData.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: fbSdoReadData: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbSdoReadData <> NULL THEN
       value := fbSdoReadData^;
       // 또는 fbSdoReadData.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbSdoReadData');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbSdoReadData) THEN
       value := fbSdoReadData.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbSdoReadData := ADR(targetVariable);
   IF fbSdoReadData = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbSdoReadData = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbSdoReadData^; // NULL 체크 없음!
value := fbSdoReadData.member; // NULL 체크 없음!

✅ 안전: IF fbSdoReadData <> NULL THEN
value := fbSdoReadData^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbSdoReadData) THEN
value := fbSdoReadData.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: fbSdoReadData: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbSdoReadData <> NULL THEN
       value := fbSdoReadData^;
       // 또는 fbSdoReadData.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbSdoReadData');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbSdoReadData) THEN
       value := fbSdoReadData.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbSdoReadData := ADR(targetVariable);
   IF fbSdoReadData = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbSdoReadData = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbSdoReadData^; // NULL 체크 없음!
value := fbSdoReadData.member; // NULL 체크 없음!

✅ 안전: IF fbSdoReadData <> NULL THEN
value := fbSdoReadData^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbSdoReadData) THEN
value := fbSdoReadData.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: FB_VG_Cal: 222줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: FB_VG_Cal = 222줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: ioCtrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioCtrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioCtrl >= (eRun - 1.0E-6) AND
      ioCtrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioCtrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioCtrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioCtrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioCtrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: ioMode = edVG_Cal: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioMode - edVG_Cal) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioMode >= (edVG_Cal - 1.0E-6) AND
      ioMode <= (edVG_Cal + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioMode >= edVG_Cal THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioMode * 10.0);
   intTarget := REAL_TO_DINT(edVG_Cal * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioMode = edVG_Cal THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioMode - edVG_Cal) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: ioCtrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioCtrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioCtrl >= (eAbort - 1.0E-6) AND
      ioCtrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioCtrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioCtrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioCtrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioCtrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: bBusy = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(bBusy - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF bBusy >= (TRUE - 1.0E-6) AND
      bBusy <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF bBusy >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(bBusy * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF bBusy = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(bBusy - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: bError = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(bError - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF bError >= (TRUE - 1.0E-6) AND
      bError <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF bError >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(bError * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF bError = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(bError - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: bBusy = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(bBusy - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF bBusy >= (FALSE - 1.0E-6) AND
      bBusy <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF bBusy >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(bBusy * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF bBusy = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(bBusy - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: ARRAY[0..5]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 0..5 >= 1 AND
      0..5 <= 10 THEN
       value := ARRAY[0..5];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 0..5, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 0..5 >= ARRAY_MIN AND 0..5 <= ARRAY_MAX THEN
       value := ARRAY[0..5];
   END_IF

예시:

❌ 위험: value := ARRAY[0..5]; // 범위 검사 없음!

✅ 안전: IF 0..5 >= 1 AND 0..5 <= 10 THEN
value := ARRAY[0..5];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: ARRAY[0..2]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 0..2 >= 1 AND
      0..2 <= 10 THEN
       value := ARRAY[0..2];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 0..2, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 0..2 >= ARRAY_MIN AND 0..2 <= ARRAY_MAX THEN
       value := ARRAY[0..2];
   END_IF

예시:

❌ 위험: value := ARRAY[0..2]; // 범위 검사 없음!

✅ 안전: IF 0..2 >= 1 AND 0..2 <= 10 THEN
value := ARRAY[0..2];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: ARRAY[0..3]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 0..3 >= 1 AND
      0..3 <= 10 THEN
       value := ARRAY[0..3];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 0..3, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 0..3 >= ARRAY_MIN AND 0..3 <= ARRAY_MAX THEN
       value := ARRAY[0..3];
   END_IF

예시:

❌ 위험: value := ARRAY[0..3]; // 범위 검사 없음!

✅ 안전: IF 0..3 >= 1 AND 0..3 <= 10 THEN
value := ARRAY[0..3];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:1

설명: 100: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 100 <> NULL THEN
       value := 100^;
       // 또는 100.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 100');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(100) THEN
       value := 100.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   100 := ADR(targetVariable);
   IF 100 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 100 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 100^; // NULL 체크 없음!
value := 100.member; // NULL 체크 없음!

✅ 안전: IF 100 <> NULL THEN
value := 100^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(100) THEN
value := 100.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:1

설명: 100: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 100 <> NULL THEN
       value := 100^;
       // 또는 100.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 100');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(100) THEN
       value := 100.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   100 := ADR(targetVariable);
   IF 100 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 100 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 100^; // NULL 체크 없음!
value := 100.member; // NULL 체크 없음!

✅ 안전: IF 100 <> NULL THEN
value := 100^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(100) THEN
value := 100.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:1

설명: LowDelay: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LowDelay <> NULL THEN
       value := LowDelay^;
       // 또는 LowDelay.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LowDelay');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LowDelay) THEN
       value := LowDelay.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LowDelay := ADR(targetVariable);
   IF LowDelay = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LowDelay = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LowDelay^; // NULL 체크 없음!
value := LowDelay.member; // NULL 체크 없음!

✅ 안전: IF LowDelay <> NULL THEN
value := LowDelay^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LowDelay) THEN
value := LowDelay.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:1

설명: Low_ioAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Low_ioAlarm <> NULL THEN
       value := Low_ioAlarm^;
       // 또는 Low_ioAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Low_ioAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Low_ioAlarm) THEN
       value := Low_ioAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Low_ioAlarm := ADR(targetVariable);
   IF Low_ioAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Low_ioAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Low_ioAlarm^; // NULL 체크 없음!
value := Low_ioAlarm.member; // NULL 체크 없음!

✅ 안전: IF Low_ioAlarm <> NULL THEN
value := Low_ioAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Low_ioAlarm) THEN
value := Low_ioAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:1

설명: HighDelay: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF HighDelay <> NULL THEN
       value := HighDelay^;
       // 또는 HighDelay.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: HighDelay');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(HighDelay) THEN
       value := HighDelay.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   HighDelay := ADR(targetVariable);
   IF HighDelay = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF HighDelay = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := HighDelay^; // NULL 체크 없음!
value := HighDelay.member; // NULL 체크 없음!

✅ 안전: IF HighDelay <> NULL THEN
value := HighDelay^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(HighDelay) THEN
value := HighDelay.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:1

설명: High_ioAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF High_ioAlarm <> NULL THEN
       value := High_ioAlarm^;
       // 또는 High_ioAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: High_ioAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(High_ioAlarm) THEN
       value := High_ioAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   High_ioAlarm := ADR(targetVariable);
   IF High_ioAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF High_ioAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := High_ioAlarm^; // NULL 체크 없음!
value := High_ioAlarm.member; // NULL 체크 없음!

✅ 안전: IF High_ioAlarm <> NULL THEN
value := High_ioAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(High_ioAlarm) THEN
value := High_ioAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig.TcPOU:1

설명: LowDelay: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LowDelay <> NULL THEN
       value := LowDelay^;
       // 또는 LowDelay.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LowDelay');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LowDelay) THEN
       value := LowDelay.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LowDelay := ADR(targetVariable);
   IF LowDelay = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LowDelay = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LowDelay^; // NULL 체크 없음!
value := LowDelay.member; // NULL 체크 없음!

✅ 안전: IF LowDelay <> NULL THEN
value := LowDelay^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LowDelay) THEN
value := LowDelay.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig.TcPOU:1

설명: Low_ioAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Low_ioAlarm <> NULL THEN
       value := Low_ioAlarm^;
       // 또는 Low_ioAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Low_ioAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Low_ioAlarm) THEN
       value := Low_ioAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Low_ioAlarm := ADR(targetVariable);
   IF Low_ioAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Low_ioAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Low_ioAlarm^; // NULL 체크 없음!
value := Low_ioAlarm.member; // NULL 체크 없음!

✅ 안전: IF Low_ioAlarm <> NULL THEN
value := Low_ioAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Low_ioAlarm) THEN
value := Low_ioAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig.TcPOU:1

설명: HighDelay: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF HighDelay <> NULL THEN
       value := HighDelay^;
       // 또는 HighDelay.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: HighDelay');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(HighDelay) THEN
       value := HighDelay.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   HighDelay := ADR(targetVariable);
   IF HighDelay = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF HighDelay = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := HighDelay^; // NULL 체크 없음!
value := HighDelay.member; // NULL 체크 없음!

✅ 안전: IF HighDelay <> NULL THEN
value := HighDelay^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(HighDelay) THEN
value := HighDelay.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig.TcPOU:1

설명: High_ioAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF High_ioAlarm <> NULL THEN
       value := High_ioAlarm^;
       // 또는 High_ioAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: High_ioAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(High_ioAlarm) THEN
       value := High_ioAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   High_ioAlarm := ADR(targetVariable);
   IF High_ioAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF High_ioAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := High_ioAlarm^; // NULL 체크 없음!
value := High_ioAlarm.member; // NULL 체크 없음!

✅ 안전: IF High_ioAlarm <> NULL THEN
value := High_ioAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(High_ioAlarm) THEN
value := High_ioAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig_Sign.TcPOU:1

설명: LowDelay: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LowDelay <> NULL THEN
       value := LowDelay^;
       // 또는 LowDelay.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LowDelay');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LowDelay) THEN
       value := LowDelay.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LowDelay := ADR(targetVariable);
   IF LowDelay = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LowDelay = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LowDelay^; // NULL 체크 없음!
value := LowDelay.member; // NULL 체크 없음!

✅ 안전: IF LowDelay <> NULL THEN
value := LowDelay^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LowDelay) THEN
value := LowDelay.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig_Sign.TcPOU:1

설명: Low_ioAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Low_ioAlarm <> NULL THEN
       value := Low_ioAlarm^;
       // 또는 Low_ioAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Low_ioAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Low_ioAlarm) THEN
       value := Low_ioAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Low_ioAlarm := ADR(targetVariable);
   IF Low_ioAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Low_ioAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Low_ioAlarm^; // NULL 체크 없음!
value := Low_ioAlarm.member; // NULL 체크 없음!

✅ 안전: IF Low_ioAlarm <> NULL THEN
value := Low_ioAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Low_ioAlarm) THEN
value := Low_ioAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig_Sign.TcPOU:1

설명: HighDelay: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF HighDelay <> NULL THEN
       value := HighDelay^;
       // 또는 HighDelay.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: HighDelay');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(HighDelay) THEN
       value := HighDelay.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   HighDelay := ADR(targetVariable);
   IF HighDelay = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF HighDelay = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := HighDelay^; // NULL 체크 없음!
value := HighDelay.member; // NULL 체크 없음!

✅ 안전: IF HighDelay <> NULL THEN
value := HighDelay^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(HighDelay) THEN
value := HighDelay.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig_Sign.TcPOU:1

설명: High_ioAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF High_ioAlarm <> NULL THEN
       value := High_ioAlarm^;
       // 또는 High_ioAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: High_ioAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(High_ioAlarm) THEN
       value := High_ioAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   High_ioAlarm := ADR(targetVariable);
   IF High_ioAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF High_ioAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := High_ioAlarm^; // NULL 체크 없음!
value := High_ioAlarm.member; // NULL 체크 없음!

✅ 안전: IF High_ioAlarm <> NULL THEN
value := High_ioAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(High_ioAlarm) THEN
value := High_ioAlarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: pGas_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pGas_Alarm <> NULL THEN
       value := pGas_Alarm^;
       // 또는 pGas_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pGas_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pGas_Alarm) THEN
       value := pGas_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pGas_Alarm := ADR(targetVariable);
   IF pGas_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pGas_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pGas_Alarm^; // NULL 체크 없음!
value := pGas_Alarm.member; // NULL 체크 없음!

✅ 안전: IF pGas_Alarm <> NULL THEN
value := pGas_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pGas_Alarm) THEN
value := pGas_Alarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: pGas_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pGas_Alarm <> NULL THEN
       value := pGas_Alarm^;
       // 또는 pGas_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pGas_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pGas_Alarm) THEN
       value := pGas_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pGas_Alarm := ADR(targetVariable);
   IF pGas_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pGas_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pGas_Alarm^; // NULL 체크 없음!
value := pGas_Alarm.member; // NULL 체크 없음!

✅ 안전: IF pGas_Alarm <> NULL THEN
value := pGas_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pGas_Alarm) THEN
value := pGas_Alarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: pGas_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pGas_Alarm <> NULL THEN
       value := pGas_Alarm^;
       // 또는 pGas_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pGas_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pGas_Alarm) THEN
       value := pGas_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pGas_Alarm := ADR(targetVariable);
   IF pGas_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pGas_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pGas_Alarm^; // NULL 체크 없음!
value := pGas_Alarm.member; // NULL 체크 없음!

✅ 안전: IF pGas_Alarm <> NULL THEN
value := pGas_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pGas_Alarm) THEN
value := pGas_Alarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: pGas_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pGas_Alarm <> NULL THEN
       value := pGas_Alarm^;
       // 또는 pGas_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pGas_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pGas_Alarm) THEN
       value := pGas_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pGas_Alarm := ADR(targetVariable);
   IF pGas_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pGas_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pGas_Alarm^; // NULL 체크 없음!
value := pGas_Alarm.member; // NULL 체크 없음!

✅ 안전: IF pGas_Alarm <> NULL THEN
value := pGas_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pGas_Alarm) THEN
value := pGas_Alarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: pGas_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pGas_Alarm <> NULL THEN
       value := pGas_Alarm^;
       // 또는 pGas_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pGas_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pGas_Alarm) THEN
       value := pGas_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pGas_Alarm := ADR(targetVariable);
   IF pGas_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pGas_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pGas_Alarm^; // NULL 체크 없음!
value := pGas_Alarm.member; // NULL 체크 없음!

✅ 안전: IF pGas_Alarm <> NULL THEN
value := pGas_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pGas_Alarm) THEN
value := pGas_Alarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: pGas_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pGas_Alarm <> NULL THEN
       value := pGas_Alarm^;
       // 또는 pGas_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pGas_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pGas_Alarm) THEN
       value := pGas_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pGas_Alarm := ADR(targetVariable);
   IF pGas_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pGas_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pGas_Alarm^; // NULL 체크 없음!
value := pGas_Alarm.member; // NULL 체크 없음!

✅ 안전: IF pGas_Alarm <> NULL THEN
value := pGas_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pGas_Alarm) THEN
value := pGas_Alarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: pGas_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pGas_Alarm <> NULL THEN
       value := pGas_Alarm^;
       // 또는 pGas_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pGas_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pGas_Alarm) THEN
       value := pGas_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pGas_Alarm := ADR(targetVariable);
   IF pGas_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pGas_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pGas_Alarm^; // NULL 체크 없음!
value := pGas_Alarm.member; // NULL 체크 없음!

✅ 안전: IF pGas_Alarm <> NULL THEN
value := pGas_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pGas_Alarm) THEN
value := pGas_Alarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: pGas_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pGas_Alarm <> NULL THEN
       value := pGas_Alarm^;
       // 또는 pGas_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pGas_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pGas_Alarm) THEN
       value := pGas_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pGas_Alarm := ADR(targetVariable);
   IF pGas_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pGas_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pGas_Alarm^; // NULL 체크 없음!
value := pGas_Alarm.member; // NULL 체크 없음!

✅ 안전: IF pGas_Alarm <> NULL THEN
value := pGas_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pGas_Alarm) THEN
value := pGas_Alarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: pGas_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pGas_Alarm <> NULL THEN
       value := pGas_Alarm^;
       // 또는 pGas_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pGas_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pGas_Alarm) THEN
       value := pGas_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pGas_Alarm := ADR(targetVariable);
   IF pGas_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pGas_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pGas_Alarm^; // NULL 체크 없음!
value := pGas_Alarm.member; // NULL 체크 없음!

✅ 안전: IF pGas_Alarm <> NULL THEN
value := pGas_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pGas_Alarm) THEN
value := pGas_Alarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: pGas_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pGas_Alarm <> NULL THEN
       value := pGas_Alarm^;
       // 또는 pGas_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pGas_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pGas_Alarm) THEN
       value := pGas_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pGas_Alarm := ADR(targetVariable);
   IF pGas_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pGas_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pGas_Alarm^; // NULL 체크 없음!
value := pGas_Alarm.member; // NULL 체크 없음!

✅ 안전: IF pGas_Alarm <> NULL THEN
value := pGas_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pGas_Alarm) THEN
value := pGas_Alarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: pGas_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pGas_Alarm <> NULL THEN
       value := pGas_Alarm^;
       // 또는 pGas_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pGas_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pGas_Alarm) THEN
       value := pGas_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pGas_Alarm := ADR(targetVariable);
   IF pGas_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pGas_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pGas_Alarm^; // NULL 체크 없음!
value := pGas_Alarm.member; // NULL 체크 없음!

✅ 안전: IF pGas_Alarm <> NULL THEN
value := pGas_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pGas_Alarm) THEN
value := pGas_Alarm.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: SEQ_Driver: 2313줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Driver = 2313줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: DX_INF_State_Module <> eModule_Disable: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Disable - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Disable + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Disable THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Disable * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Disable THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: ARRAY[1..100]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..100 >= 1 AND
      1..100 <= 10 THEN
       value := ARRAY[1..100];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..100, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..100 >= ARRAY_MIN AND 1..100 <= ARRAY_MAX THEN
       value := ARRAY[1..100];
   END_IF

예시:

❌ 위험: value := ARRAY[1..100]; // 범위 검사 없음!

✅ 안전: IF 1..100 >= 1 AND 1..100 <= 10 THEN
value := ARRAY[1..100];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: ARRAY[1..20]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..20 >= 1 AND
      1..20 <= 10 THEN
       value := ARRAY[1..20];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..20, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..20 >= ARRAY_MIN AND 1..20 <= ARRAY_MAX THEN
       value := ARRAY[1..20];
   END_IF

예시:

❌ 위험: value := ARRAY[1..20]; // 범위 검사 없음!

✅ 안전: IF 1..20 >= 1 AND 1..20 <= 10 THEN
value := ARRAY[1..20];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: ARRAY[1..20]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..20 >= 1 AND
      1..20 <= 10 THEN
       value := ARRAY[1..20];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..20, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..20 >= ARRAY_MIN AND 1..20 <= ARRAY_MAX THEN
       value := ARRAY[1..20];
   END_IF

예시:

❌ 위험: value := ARRAY[1..20]; // 범위 검사 없음!

✅ 안전: IF 1..20 >= 1 AND 1..20 <= 10 THEN
value := ARRAY[1..20];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: ARRAY[1..cMAX_MFC]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_MFC >= 1 AND
      1..cMAX_MFC <= 10 THEN
       value := ARRAY[1..cMAX_MFC];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_MFC, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_MFC >= ARRAY_MIN AND 1..cMAX_MFC <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_MFC];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_MFC]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_MFC >= 1 AND 1..cMAX_MFC <= 10 THEN
value := ARRAY[1..cMAX_MFC];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: ARRAY[1..cMAX_MFC]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_MFC >= 1 AND
      1..cMAX_MFC <= 10 THEN
       value := ARRAY[1..cMAX_MFC];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_MFC, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_MFC >= ARRAY_MIN AND 1..cMAX_MFC <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_MFC];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_MFC]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_MFC >= 1 AND 1..cMAX_MFC <= 10 THEN
value := ARRAY[1..cMAX_MFC];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: ARRAY[1..cMAX_MFC]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_MFC >= 1 AND
      1..cMAX_MFC <= 10 THEN
       value := ARRAY[1..cMAX_MFC];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_MFC, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_MFC >= ARRAY_MIN AND 1..cMAX_MFC <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_MFC];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_MFC]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_MFC >= 1 AND 1..cMAX_MFC <= 10 THEN
value := ARRAY[1..cMAX_MFC];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Gas_Parameter[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Gas_Parameter[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Gas_Parameter[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Gas_Parameter[i];
   END_IF

예시:

❌ 위험: value := Gas_Parameter[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Gas_Parameter[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Warning_Low[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Warning_Low[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Warning_Low[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Warning_Low[i];
   END_IF

예시:

❌ 위험: value := Warning_Low[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Warning_Low[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Gas_Parameter[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Gas_Parameter[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Gas_Parameter[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Gas_Parameter[i];
   END_IF

예시:

❌ 위험: value := Gas_Parameter[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Gas_Parameter[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Warning_High[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Warning_High[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Warning_High[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Warning_High[i];
   END_IF

예시:

❌ 위험: value := Warning_High[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Warning_High[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Gas_Parameter[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Gas_Parameter[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Gas_Parameter[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Gas_Parameter[i];
   END_IF

예시:

❌ 위험: value := Gas_Parameter[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Gas_Parameter[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Abort_Low[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Abort_Low[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Abort_Low[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Abort_Low[i];
   END_IF

예시:

❌ 위험: value := Abort_Low[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Abort_Low[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Gas_Parameter[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Gas_Parameter[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Gas_Parameter[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Gas_Parameter[i];
   END_IF

예시:

❌ 위험: value := Gas_Parameter[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Gas_Parameter[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Abort_High[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Abort_High[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Abort_High[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Abort_High[i];
   END_IF

예시:

❌ 위험: value := Abort_High[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Abort_High[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Gas_Parameter[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Gas_Parameter[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Gas_Parameter[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Gas_Parameter[i];
   END_IF

예시:

❌ 위험: value := Gas_Parameter[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Gas_Parameter[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: DeadBand[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DeadBand[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DeadBand[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DeadBand[i];
   END_IF

예시:

❌ 위험: value := DeadBand[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DeadBand[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Gas_Parameter[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Gas_Parameter[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Gas_Parameter[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Gas_Parameter[i];
   END_IF

예시:

❌ 위험: value := Gas_Parameter[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Gas_Parameter[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Warning_Delay[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Warning_Delay[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Warning_Delay[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Warning_Delay[i];
   END_IF

예시:

❌ 위험: value := Warning_Delay[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Warning_Delay[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Gas_Parameter[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Gas_Parameter[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Gas_Parameter[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Gas_Parameter[i];
   END_IF

예시:

❌ 위험: value := Gas_Parameter[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Gas_Parameter[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Abort_Delay[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Abort_Delay[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Abort_Delay[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Abort_Delay[i];
   END_IF

예시:

❌ 위험: value := Abort_Delay[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Abort_Delay[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Gas_Parameter[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Gas_Parameter[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Gas_Parameter[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Gas_Parameter[i];
   END_IF

예시:

❌ 위험: value := Gas_Parameter[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Gas_Parameter[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: DeadBand_Delay[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DeadBand_Delay[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DeadBand_Delay[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DeadBand_Delay[i];
   END_IF

예시:

❌ 위험: value := DeadBand_Delay[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DeadBand_Delay[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Gas_Parameter[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Gas_Parameter[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Gas_Parameter[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Gas_Parameter[i];
   END_IF

예시:

❌ 위험: value := Gas_Parameter[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Gas_Parameter[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Warning_Condition[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Warning_Condition[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Warning_Condition[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Warning_Condition[i];
   END_IF

예시:

❌ 위험: value := Warning_Condition[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Warning_Condition[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Gas_Parameter[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Gas_Parameter[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Gas_Parameter[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Gas_Parameter[i];
   END_IF

예시:

❌ 위험: value := Gas_Parameter[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Gas_Parameter[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Abort_Condition[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Abort_Condition[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Abort_Condition[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Abort_Condition[i];
   END_IF

예시:

❌ 위험: value := Abort_Condition[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Abort_Condition[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Gas_Parameter[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Gas_Parameter[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Gas_Parameter[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Gas_Parameter[i];
   END_IF

예시:

❌ 위험: value := Gas_Parameter[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Gas_Parameter[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Dead_Condition[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Dead_Condition[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Dead_Condition[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Dead_Condition[i];
   END_IF

예시:

❌ 위험: value := Dead_Condition[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Dead_Condition[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Gas_Parameter[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Gas_Parameter[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Gas_Parameter[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Gas_Parameter[i];
   END_IF

예시:

❌ 위험: value := Gas_Parameter[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Gas_Parameter[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Gas_Parameter[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Gas_Parameter[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Gas_Parameter[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Gas_Parameter[i];
   END_IF

예시:

❌ 위험: value := Gas_Parameter[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Gas_Parameter[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: Gas_Parameter[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Gas_Parameter[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Gas_Parameter[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Gas_Parameter[i];
   END_IF

예시:

❌ 위험: value := Gas_Parameter[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Gas_Parameter[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: DX_MFC_Mode[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DX_MFC_Mode[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DX_MFC_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DX_MFC_Mode[i];
   END_IF

예시:

❌ 위험: value := DX_MFC_Mode[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DX_MFC_Mode[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:1

설명: SEQ_Driver_APC: 738줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Driver_APC = 738줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:1

설명: Step <> 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Step - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Step >= (0 - 1.0E-6) AND
      Step <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Step >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Step * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Step = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Step - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:1

설명: iMode = oldMode_T: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iMode - oldMode_T) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iMode >= (oldMode_T - 1.0E-6) AND
      iMode <= (oldMode_T + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iMode >= oldMode_T THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iMode * 10.0);
   intTarget := REAL_TO_DINT(oldMode_T * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iMode = oldMode_T THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iMode - oldMode_T) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:1

설명: iMode = edAPC_Unknown: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iMode - edAPC_Unknown) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iMode >= (edAPC_Unknown - 1.0E-6) AND
      iMode <= (edAPC_Unknown + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iMode >= edAPC_Unknown THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iMode * 10.0);
   intTarget := REAL_TO_DINT(edAPC_Unknown * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iMode = edAPC_Unknown THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iMode - edAPC_Unknown) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:1

설명: iMode = edAPC_Pressure1: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iMode - edAPC_Pressure1) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iMode >= (edAPC_Pressure1 - 1.0E-6) AND
      iMode <= (edAPC_Pressure1 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iMode >= edAPC_Pressure1 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iMode * 10.0);
   intTarget := REAL_TO_DINT(edAPC_Pressure1 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iMode = edAPC_Pressure1 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iMode - edAPC_Pressure1) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:1

설명: ARRAY[1..cMAX_APC_PID]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_APC_PID >= 1 AND
      1..cMAX_APC_PID <= 10 THEN
       value := ARRAY[1..cMAX_APC_PID];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_APC_PID, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_APC_PID >= ARRAY_MIN AND 1..cMAX_APC_PID <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_APC_PID];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_APC_PID]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_APC_PID >= 1 AND 1..cMAX_APC_PID <= 10 THEN
value := ARRAY[1..cMAX_APC_PID];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:1

설명: ARRAY[1..cMAX_APC_PID]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_APC_PID >= 1 AND
      1..cMAX_APC_PID <= 10 THEN
       value := ARRAY[1..cMAX_APC_PID];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_APC_PID, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_APC_PID >= ARRAY_MIN AND 1..cMAX_APC_PID <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_APC_PID];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_APC_PID]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_APC_PID >= 1 AND 1..cMAX_APC_PID <= 10 THEN
value := ARRAY[1..cMAX_APC_PID];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:1

설명: ARRAY[1..cMAX_APC_PID]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_APC_PID >= 1 AND
      1..cMAX_APC_PID <= 10 THEN
       value := ARRAY[1..cMAX_APC_PID];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_APC_PID, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_APC_PID >= ARRAY_MIN AND 1..cMAX_APC_PID <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_APC_PID];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_APC_PID]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_APC_PID >= 1 AND 1..cMAX_APC_PID <= 10 THEN
value := ARRAY[1..cMAX_APC_PID];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:1

설명: ARRAY[1..cMAX_APC_PID]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_APC_PID >= 1 AND
      1..cMAX_APC_PID <= 10 THEN
       value := ARRAY[1..cMAX_APC_PID];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_APC_PID, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_APC_PID >= ARRAY_MIN AND 1..cMAX_APC_PID <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_APC_PID];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_APC_PID]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_APC_PID >= 1 AND 1..cMAX_APC_PID <= 10 THEN
value := ARRAY[1..cMAX_APC_PID];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:1

설명: ARRAY[1..cMAX_APC_PID]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_APC_PID >= 1 AND
      1..cMAX_APC_PID <= 10 THEN
       value := ARRAY[1..cMAX_APC_PID];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_APC_PID, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_APC_PID >= ARRAY_MIN AND 1..cMAX_APC_PID <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_APC_PID];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_APC_PID]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_APC_PID >= 1 AND 1..cMAX_APC_PID <= 10 THEN
value := ARRAY[1..cMAX_APC_PID];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:1

설명: ARRAY[1..cMAX_APC_PID]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_APC_PID >= 1 AND
      1..cMAX_APC_PID <= 10 THEN
       value := ARRAY[1..cMAX_APC_PID];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_APC_PID, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_APC_PID >= ARRAY_MIN AND 1..cMAX_APC_PID <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_APC_PID];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_APC_PID]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_APC_PID >= 1 AND 1..cMAX_APC_PID <= 10 THEN
value := ARRAY[1..cMAX_APC_PID];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: FFU_AlarmReset: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF FFU_AlarmReset <> NULL THEN
       value := FFU_AlarmReset^;
       // 또는 FFU_AlarmReset.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: FFU_AlarmReset');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(FFU_AlarmReset) THEN
       value := FFU_AlarmReset.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   FFU_AlarmReset := ADR(targetVariable);
   IF FFU_AlarmReset = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF FFU_AlarmReset = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := FFU_AlarmReset^; // NULL 체크 없음!
value := FFU_AlarmReset.member; // NULL 체크 없음!

✅ 안전: IF FFU_AlarmReset <> NULL THEN
value := FFU_AlarmReset^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(FFU_AlarmReset) THEN
value := FFU_AlarmReset.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: FFU_AlarmReset: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF FFU_AlarmReset <> NULL THEN
       value := FFU_AlarmReset^;
       // 또는 FFU_AlarmReset.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: FFU_AlarmReset');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(FFU_AlarmReset) THEN
       value := FFU_AlarmReset.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   FFU_AlarmReset := ADR(targetVariable);
   IF FFU_AlarmReset = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF FFU_AlarmReset = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := FFU_AlarmReset^; // NULL 체크 없음!
value := FFU_AlarmReset.member; // NULL 체크 없음!

✅ 안전: IF FFU_AlarmReset <> NULL THEN
value := FFU_AlarmReset^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(FFU_AlarmReset) THEN
value := FFU_AlarmReset.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: FFU_Reset_On1s: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF FFU_Reset_On1s <> NULL THEN
       value := FFU_Reset_On1s^;
       // 또는 FFU_Reset_On1s.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: FFU_Reset_On1s');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(FFU_Reset_On1s) THEN
       value := FFU_Reset_On1s.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   FFU_Reset_On1s := ADR(targetVariable);
   IF FFU_Reset_On1s = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF FFU_Reset_On1s = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := FFU_Reset_On1s^; // NULL 체크 없음!
value := FFU_Reset_On1s.member; // NULL 체크 없음!

✅ 안전: IF FFU_Reset_On1s <> NULL THEN
value := FFU_Reset_On1s^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(FFU_Reset_On1s) THEN
value := FFU_Reset_On1s.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: Simulation = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Simulation - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Simulation >= (FALSE - 1.0E-6) AND
      Simulation <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Simulation >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Simulation * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Simulation = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Simulation - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: DO_FFU_Command <> edFFU_Set: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DO_FFU_Command - edFFU_Set) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DO_FFU_Command >= (edFFU_Set - 1.0E-6) AND
      DO_FFU_Command <= (edFFU_Set + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DO_FFU_Command >= edFFU_Set THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DO_FFU_Command * 10.0);
   intTarget := REAL_TO_DINT(edFFU_Set * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DO_FFU_Command = edFFU_Set THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DO_FFU_Command - edFFU_Set) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: DO_FFU_Alarm_Reset = 1: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DO_FFU_Alarm_Reset - 1) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DO_FFU_Alarm_Reset >= (1 - 1.0E-6) AND
      DO_FFU_Alarm_Reset <= (1 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DO_FFU_Alarm_Reset >= 1 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DO_FFU_Alarm_Reset * 10.0);
   intTarget := REAL_TO_DINT(1 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DO_FFU_Alarm_Reset = 1 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DO_FFU_Alarm_Reset - 1) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: DO_FFU_Command = edFFU_Set: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DO_FFU_Command - edFFU_Set) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DO_FFU_Command >= (edFFU_Set - 1.0E-6) AND
      DO_FFU_Command <= (edFFU_Set + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DO_FFU_Command >= edFFU_Set THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DO_FFU_Command * 10.0);
   intTarget := REAL_TO_DINT(edFFU_Set * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DO_FFU_Command = edFFU_Set THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DO_FFU_Command - edFFU_Set) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: DX_INF_State_Module <> eModule_Disable: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Disable - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Disable + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Disable THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Disable * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Disable THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: 0 = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(0 - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF 0 >= (TRUE - 1.0E-6) AND
      0 <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF 0 >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(0 * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF 0 = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(0 - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: 2 = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(2 - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF 2 >= (TRUE - 1.0E-6) AND
      2 <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF 2 >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(2 * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF 2 = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(2 - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: 3 = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(3 - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF 3 >= (TRUE - 1.0E-6) AND
      3 <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF 3 >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(3 * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF 3 = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(3 - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: 6 = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(6 - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF 6 >= (TRUE - 1.0E-6) AND
      6 <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF 6 >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(6 * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF 6 = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(6 - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: 0 = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(0 - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF 0 >= (TRUE - 1.0E-6) AND
      0 <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF 0 >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(0 * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF 0 = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(0 - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: 2 = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(2 - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF 2 >= (TRUE - 1.0E-6) AND
      2 <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF 2 >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(2 * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF 2 = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(2 - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: 3 = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(3 - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF 3 >= (TRUE - 1.0E-6) AND
      3 <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF 3 >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(3 * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF 3 = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(3 - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: 6 = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(6 - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF 6 >= (TRUE - 1.0E-6) AND
      6 <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF 6 >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(6 * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF 6 = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(6 - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: 9 = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(9 - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF 9 >= (TRUE - 1.0E-6) AND
      9 <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF 9 >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(9 * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF 9 = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(9 - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ARRAY[1..cMAX_FFU]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_FFU >= 1 AND
      1..cMAX_FFU <= 10 THEN
       value := ARRAY[1..cMAX_FFU];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_FFU, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_FFU >= ARRAY_MIN AND 1..cMAX_FFU <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_FFU];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_FFU]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_FFU >= 1 AND 1..cMAX_FFU <= 10 THEN
value := ARRAY[1..cMAX_FFU];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ARRAY[1..cMAX_FFU]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_FFU >= 1 AND
      1..cMAX_FFU <= 10 THEN
       value := ARRAY[1..cMAX_FFU];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_FFU, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_FFU >= ARRAY_MIN AND 1..cMAX_FFU <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_FFU];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_FFU]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_FFU >= 1 AND 1..cMAX_FFU <= 10 THEN
value := ARRAY[1..cMAX_FFU];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ARRAY[1..cMAX_FFU]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_FFU >= 1 AND
      1..cMAX_FFU <= 10 THEN
       value := ARRAY[1..cMAX_FFU];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_FFU, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_FFU >= ARRAY_MIN AND 1..cMAX_FFU <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_FFU];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_FFU]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_FFU >= 1 AND 1..cMAX_FFU <= 10 THEN
value := ARRAY[1..cMAX_FFU];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ARRAY[1..cMAX_FFU]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_FFU >= 1 AND
      1..cMAX_FFU <= 10 THEN
       value := ARRAY[1..cMAX_FFU];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_FFU, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_FFU >= ARRAY_MIN AND 1..cMAX_FFU <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_FFU];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_FFU]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_FFU >= 1 AND 1..cMAX_FFU <= 10 THEN
value := ARRAY[1..cMAX_FFU];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: tFFU_Fan_Off_Time[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := tFFU_Fan_Off_Time[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := tFFU_Fan_Off_Time[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := tFFU_Fan_Off_Time[i];
   END_IF

예시:

❌ 위험: value := tFFU_Fan_Off_Time[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := tFFU_Fan_Off_Time[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: AI_FFU_Cur_Speed[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := AI_FFU_Cur_Speed[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := AI_FFU_Cur_Speed[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := AI_FFU_Cur_Speed[i];
   END_IF

예시:

❌ 위험: value := AI_FFU_Cur_Speed[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := AI_FFU_Cur_Speed[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: fbAlarm[16011 + i - 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 16011 + i - 1 >= 1 AND
      16011 + i - 1 <= 10 THEN
       value := fbAlarm[16011 + i - 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 16011 + i - 1, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 16011 + i - 1 >= ARRAY_MIN AND 16011 + i - 1 <= ARRAY_MAX THEN
       value := fbAlarm[16011 + i - 1];
   END_IF

예시:

❌ 위험: value := fbAlarm[16011 + i - 1]; // 범위 검사 없음!

✅ 안전: IF 16011 + i - 1 >= 1 AND 16011 + i - 1 <= 10 THEN
value := fbAlarm[16011 + i - 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: tFFU_Fan_Rpm_Low_Time[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := tFFU_Fan_Rpm_Low_Time[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := tFFU_Fan_Rpm_Low_Time[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := tFFU_Fan_Rpm_Low_Time[i];
   END_IF

예시:

❌ 위험: value := tFFU_Fan_Rpm_Low_Time[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := tFFU_Fan_Rpm_Low_Time[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: AI_FFU_Cur_Speed[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := AI_FFU_Cur_Speed[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := AI_FFU_Cur_Speed[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := AI_FFU_Cur_Speed[i];
   END_IF

예시:

❌ 위험: value := AI_FFU_Cur_Speed[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := AI_FFU_Cur_Speed[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: AX_ITK_PMC_FFU_Procee_RPM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := AX_ITK_PMC_FFU_Procee_RPM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := AX_ITK_PMC_FFU_Procee_RPM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := AX_ITK_PMC_FFU_Procee_RPM[i];
   END_IF

예시:

❌ 위험: value := AX_ITK_PMC_FFU_Procee_RPM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := AX_ITK_PMC_FFU_Procee_RPM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: fbAlarm[16051 + i - 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 16051 + i - 1 >= 1 AND
      16051 + i - 1 <= 10 THEN
       value := fbAlarm[16051 + i - 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 16051 + i - 1, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 16051 + i - 1 >= ARRAY_MIN AND 16051 + i - 1 <= ARRAY_MAX THEN
       value := fbAlarm[16051 + i - 1];
   END_IF

예시:

❌ 위험: value := fbAlarm[16051 + i - 1]; // 범위 검사 없음!

✅ 안전: IF 16051 + i - 1 >= 1 AND 16051 + i - 1 <= 10 THEN
value := fbAlarm[16051 + i - 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ioAO_ECAT_FFU_FAN_RPM_SET[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAO_ECAT_FFU_FAN_RPM_SET[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAO_ECAT_FFU_FAN_RPM_SET[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAO_ECAT_FFU_FAN_RPM_SET[i];
   END_IF

예시:

❌ 위험: value := ioAO_ECAT_FFU_FAN_RPM_SET[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAO_ECAT_FFU_FAN_RPM_SET[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: AO_FFU_Set_Speed[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := AO_FFU_Set_Speed[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := AO_FFU_Set_Speed[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := AO_FFU_Set_Speed[i];
   END_IF

예시:

❌ 위험: value := AO_FFU_Set_Speed[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := AO_FFU_Set_Speed[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: AI_FFU_Cur_Speed[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := AI_FFU_Cur_Speed[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := AI_FFU_Cur_Speed[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := AI_FFU_Cur_Speed[i];
   END_IF

예시:

❌ 위험: value := AI_FFU_Cur_Speed[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := AI_FFU_Cur_Speed[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ioAI_ECAT_FFU_FAN_RPM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAI_ECAT_FFU_FAN_RPM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAI_ECAT_FFU_FAN_RPM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAI_ECAT_FFU_FAN_RPM[i];
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_FFU_FAN_RPM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAI_ECAT_FFU_FAN_RPM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: AI_FFU_High_Limit[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := AI_FFU_High_Limit[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := AI_FFU_High_Limit[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := AI_FFU_High_Limit[i];
   END_IF

예시:

❌ 위험: value := AI_FFU_High_Limit[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := AI_FFU_High_Limit[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ioAI_ECAT_FFU_FAN_RPM_HIGH_LIMIT[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAI_ECAT_FFU_FAN_RPM_HIGH_LIMIT[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAI_ECAT_FFU_FAN_RPM_HIGH_LIMIT[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAI_ECAT_FFU_FAN_RPM_HIGH_LIMIT[i];
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_FFU_FAN_RPM_HIGH_LIMIT[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAI_ECAT_FFU_FAN_RPM_HIGH_LIMIT[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: AI_FFU_Low_Limit[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := AI_FFU_Low_Limit[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := AI_FFU_Low_Limit[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := AI_FFU_Low_Limit[i];
   END_IF

예시:

❌ 위험: value := AI_FFU_Low_Limit[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := AI_FFU_Low_Limit[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ioAI_ECAT_FFU_FAN_RPM_LOW_LIMIT[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAI_ECAT_FFU_FAN_RPM_LOW_LIMIT[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAI_ECAT_FFU_FAN_RPM_LOW_LIMIT[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAI_ECAT_FFU_FAN_RPM_LOW_LIMIT[i];
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_FFU_FAN_RPM_LOW_LIMIT[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAI_ECAT_FFU_FAN_RPM_LOW_LIMIT[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ioAO_ECAT_FFU_FAN_RPM_HIGH_LIMIT[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAO_ECAT_FFU_FAN_RPM_HIGH_LIMIT[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAO_ECAT_FFU_FAN_RPM_HIGH_LIMIT[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAO_ECAT_FFU_FAN_RPM_HIGH_LIMIT[i];
   END_IF

예시:

❌ 위험: value := ioAO_ECAT_FFU_FAN_RPM_HIGH_LIMIT[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAO_ECAT_FFU_FAN_RPM_HIGH_LIMIT[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: AX_CFG_FFU_High_Limit[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := AX_CFG_FFU_High_Limit[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := AX_CFG_FFU_High_Limit[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := AX_CFG_FFU_High_Limit[i];
   END_IF

예시:

❌ 위험: value := AX_CFG_FFU_High_Limit[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := AX_CFG_FFU_High_Limit[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ioAO_ECAT_FFU_FAN_RPM_LOW_LIMIT[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAO_ECAT_FFU_FAN_RPM_LOW_LIMIT[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAO_ECAT_FFU_FAN_RPM_LOW_LIMIT[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAO_ECAT_FFU_FAN_RPM_LOW_LIMIT[i];
   END_IF

예시:

❌ 위험: value := ioAO_ECAT_FFU_FAN_RPM_LOW_LIMIT[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAO_ECAT_FFU_FAN_RPM_LOW_LIMIT[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: AX_CFG_FFU_Low_Limit[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := AX_CFG_FFU_Low_Limit[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := AX_CFG_FFU_Low_Limit[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := AX_CFG_FFU_Low_Limit[i];
   END_IF

예시:

❌ 위험: value := AX_CFG_FFU_Low_Limit[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := AX_CFG_FFU_Low_Limit[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ControllerAlarm[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ControllerAlarm[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ControllerAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ControllerAlarm[i];
   END_IF

예시:

❌ 위험: value := ControllerAlarm[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ControllerAlarm[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ioAI_ECAT_FFU_FAN_ALARM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAI_ECAT_FFU_FAN_ALARM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAI_ECAT_FFU_FAN_ALARM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAI_ECAT_FFU_FAN_ALARM[i];
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_FFU_FAN_ALARM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAI_ECAT_FFU_FAN_ALARM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ControllerAlarm[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ControllerAlarm[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ControllerAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ControllerAlarm[i];
   END_IF

예시:

❌ 위험: value := ControllerAlarm[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ControllerAlarm[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: fbAlarm[16031 + i - 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 16031 + i - 1 >= 1 AND
      16031 + i - 1 <= 10 THEN
       value := fbAlarm[16031 + i - 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 16031 + i - 1, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 16031 + i - 1 >= ARRAY_MIN AND 16031 + i - 1 <= ARRAY_MAX THEN
       value := fbAlarm[16031 + i - 1];
   END_IF

예시:

❌ 위험: value := fbAlarm[16031 + i - 1]; // 범위 검사 없음!

✅ 안전: IF 16031 + i - 1 >= 1 AND 16031 + i - 1 <= 10 THEN
value := fbAlarm[16031 + i - 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ControllerAlarm[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ControllerAlarm[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ControllerAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ControllerAlarm[i];
   END_IF

예시:

❌ 위험: value := ControllerAlarm[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ControllerAlarm[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: fbAlarm[16041 + i - 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 16041 + i - 1 >= 1 AND
      16041 + i - 1 <= 10 THEN
       value := fbAlarm[16041 + i - 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 16041 + i - 1, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 16041 + i - 1 >= ARRAY_MIN AND 16041 + i - 1 <= ARRAY_MAX THEN
       value := fbAlarm[16041 + i - 1];
   END_IF

예시:

❌ 위험: value := fbAlarm[16041 + i - 1]; // 범위 검사 없음!

✅ 안전: IF 16041 + i - 1 >= 1 AND 16041 + i - 1 <= 10 THEN
value := fbAlarm[16041 + i - 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ControllerAlarm[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ControllerAlarm[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ControllerAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ControllerAlarm[i];
   END_IF

예시:

❌ 위험: value := ControllerAlarm[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ControllerAlarm[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: fbAlarm[16051 + i - 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 16051 + i - 1 >= 1 AND
      16051 + i - 1 <= 10 THEN
       value := fbAlarm[16051 + i - 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 16051 + i - 1, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 16051 + i - 1 >= ARRAY_MIN AND 16051 + i - 1 <= ARRAY_MAX THEN
       value := fbAlarm[16051 + i - 1];
   END_IF

예시:

❌ 위험: value := fbAlarm[16051 + i - 1]; // 범위 검사 없음!

✅ 안전: IF 16051 + i - 1 >= 1 AND 16051 + i - 1 <= 10 THEN
value := fbAlarm[16051 + i - 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ControllerAlarm[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ControllerAlarm[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ControllerAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ControllerAlarm[i];
   END_IF

예시:

❌ 위험: value := ControllerAlarm[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ControllerAlarm[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: fbAlarm[16061 + i - 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 16061 + i - 1 >= 1 AND
      16061 + i - 1 <= 10 THEN
       value := fbAlarm[16061 + i - 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 16061 + i - 1, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 16061 + i - 1 >= ARRAY_MIN AND 16061 + i - 1 <= ARRAY_MAX THEN
       value := fbAlarm[16061 + i - 1];
   END_IF

예시:

❌ 위험: value := fbAlarm[16061 + i - 1]; // 범위 검사 없음!

✅ 안전: IF 16061 + i - 1 >= 1 AND 16061 + i - 1 <= 10 THEN
value := fbAlarm[16061 + i - 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ControllerAlarm[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ControllerAlarm[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ControllerAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ControllerAlarm[i];
   END_IF

예시:

❌ 위험: value := ControllerAlarm[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ControllerAlarm[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ControllerAlarm[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ControllerAlarm[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ControllerAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ControllerAlarm[i];
   END_IF

예시:

❌ 위험: value := ControllerAlarm[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ControllerAlarm[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ControllerAlarm[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ControllerAlarm[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ControllerAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ControllerAlarm[i];
   END_IF

예시:

❌ 위험: value := ControllerAlarm[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ControllerAlarm[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ControllerAlarm[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ControllerAlarm[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ControllerAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ControllerAlarm[i];
   END_IF

예시:

❌ 위험: value := ControllerAlarm[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ControllerAlarm[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: ControllerAlarm[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ControllerAlarm[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ControllerAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ControllerAlarm[i];
   END_IF

예시:

❌ 위험: value := ControllerAlarm[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ControllerAlarm[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: DI_FFU_Run_Status[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DI_FFU_Run_Status[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DI_FFU_Run_Status[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DI_FFU_Run_Status[i];
   END_IF

예시:

❌ 위험: value := DI_FFU_Run_Status[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DI_FFU_Run_Status[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: DI_FFU_Run_Status[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DI_FFU_Run_Status[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DI_FFU_Run_Status[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DI_FFU_Run_Status[i];
   END_IF

예시:

❌ 위험: value := DI_FFU_Run_Status[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DI_FFU_Run_Status[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: 206000: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 206000 <> NULL THEN
       value := 206000^;
       // 또는 206000.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 206000');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(206000) THEN
       value := 206000.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   206000 := ADR(targetVariable);
   IF 206000 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 206000 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 206000^; // NULL 체크 없음!
value := 206000.member; // NULL 체크 없음!

✅ 안전: IF 206000 <> NULL THEN
value := 206000^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(206000) THEN
value := 206000.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: 20: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 20 <> NULL THEN
       value := 20^;
       // 또는 20.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 20');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(20) THEN
       value := 20.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   20 := ADR(targetVariable);
   IF 20 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 20 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 20^; // NULL 체크 없음!
value := 20.member; // NULL 체크 없음!

✅ 안전: IF 20 <> NULL THEN
value := 20^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(20) THEN
value := 20.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: 1000000: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 1000000 <> NULL THEN
       value := 1000000^;
       // 또는 1000000.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 1000000');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(1000000) THEN
       value := 1000000.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   1000000 := ADR(targetVariable);
   IF 1000000 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 1000000 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 1000000^; // NULL 체크 없음!
value := 1000000.member; // NULL 체크 없음!

✅ 안전: IF 1000000 <> NULL THEN
value := 1000000^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(1000000) THEN
value := 1000000.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: 100: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 100 <> NULL THEN
       value := 100^;
       // 또는 100.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 100');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(100) THEN
       value := 100.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   100 := ADR(targetVariable);
   IF 100 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 100 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 100^; // NULL 체크 없음!
value := 100.member; // NULL 체크 없음!

✅ 안전: IF 100 <> NULL THEN
value := 100^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(100) THEN
value := 100.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: 100: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 100 <> NULL THEN
       value := 100^;
       // 또는 100.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 100');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(100) THEN
       value := 100.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   100 := ADR(targetVariable);
   IF 100 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 100 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 100^; // NULL 체크 없음!
value := 100.member; // NULL 체크 없음!

✅ 안전: IF 100 <> NULL THEN
value := 100^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(100) THEN
value := 100.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: TimeOut: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF TimeOut <> NULL THEN
       value := TimeOut^;
       // 또는 TimeOut.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: TimeOut');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(TimeOut) THEN
       value := TimeOut.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   TimeOut := ADR(targetVariable);
   IF TimeOut = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF TimeOut = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := TimeOut^; // NULL 체크 없음!
value := TimeOut.member; // NULL 체크 없음!

✅ 안전: IF TimeOut <> NULL THEN
value := TimeOut^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(TimeOut) THEN
value := TimeOut.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: tConnect: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF tConnect <> NULL THEN
       value := tConnect^;
       // 또는 tConnect.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: tConnect');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(tConnect) THEN
       value := tConnect.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   tConnect := ADR(targetVariable);
   IF tConnect = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF tConnect = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := tConnect^; // NULL 체크 없음!
value := tConnect.member; // NULL 체크 없음!

✅ 안전: IF tConnect <> NULL THEN
value := tConnect^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(tConnect) THEN
value := tConnect.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: Delay_Time: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Delay_Time <> NULL THEN
       value := Delay_Time^;
       // 또는 Delay_Time.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Delay_Time');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Delay_Time) THEN
       value := Delay_Time.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Delay_Time := ADR(targetVariable);
   IF Delay_Time = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Delay_Time = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Delay_Time^; // NULL 체크 없음!
value := Delay_Time.member; // NULL 체크 없음!

✅ 안전: IF Delay_Time <> NULL THEN
value := Delay_Time^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Delay_Time) THEN
value := Delay_Time.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: ComReceiveData: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ComReceiveData <> NULL THEN
       value := ComReceiveData^;
       // 또는 ComReceiveData.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ComReceiveData');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ComReceiveData) THEN
       value := ComReceiveData.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ComReceiveData := ADR(targetVariable);
   IF ComReceiveData = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ComReceiveData = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ComReceiveData^; // NULL 체크 없음!
value := ComReceiveData.member; // NULL 체크 없음!

✅ 안전: IF ComReceiveData <> NULL THEN
value := ComReceiveData^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ComReceiveData) THEN
value := ComReceiveData.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: ComReceiveData: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ComReceiveData <> NULL THEN
       value := ComReceiveData^;
       // 또는 ComReceiveData.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ComReceiveData');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ComReceiveData) THEN
       value := ComReceiveData.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ComReceiveData := ADR(targetVariable);
   IF ComReceiveData = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ComReceiveData = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ComReceiveData^; // NULL 체크 없음!
value := ComReceiveData.member; // NULL 체크 없음!

✅ 안전: IF ComReceiveData <> NULL THEN
value := ComReceiveData^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ComReceiveData) THEN
value := ComReceiveData.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: Delay_Time: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Delay_Time <> NULL THEN
       value := Delay_Time^;
       // 또는 Delay_Time.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Delay_Time');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Delay_Time) THEN
       value := Delay_Time.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Delay_Time := ADR(targetVariable);
   IF Delay_Time = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Delay_Time = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Delay_Time^; // NULL 체크 없음!
value := Delay_Time.member; // NULL 체크 없음!

✅ 안전: IF Delay_Time <> NULL THEN
value := Delay_Time^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Delay_Time) THEN
value := Delay_Time.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: Delay_Time: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Delay_Time <> NULL THEN
       value := Delay_Time^;
       // 또는 Delay_Time.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Delay_Time');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Delay_Time) THEN
       value := Delay_Time.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Delay_Time := ADR(targetVariable);
   IF Delay_Time = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Delay_Time = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Delay_Time^; // NULL 체크 없음!
value := Delay_Time.member; // NULL 체크 없음!

✅ 안전: IF Delay_Time <> NULL THEN
value := Delay_Time^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Delay_Time) THEN
value := Delay_Time.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: ComReceiveData: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ComReceiveData <> NULL THEN
       value := ComReceiveData^;
       // 또는 ComReceiveData.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ComReceiveData');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ComReceiveData) THEN
       value := ComReceiveData.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ComReceiveData := ADR(targetVariable);
   IF ComReceiveData = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ComReceiveData = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ComReceiveData^; // NULL 체크 없음!
value := ComReceiveData.member; // NULL 체크 없음!

✅ 안전: IF ComReceiveData <> NULL THEN
value := ComReceiveData^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ComReceiveData) THEN
value := ComReceiveData.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: ComReceiveData: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ComReceiveData <> NULL THEN
       value := ComReceiveData^;
       // 또는 ComReceiveData.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ComReceiveData');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ComReceiveData) THEN
       value := ComReceiveData.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ComReceiveData := ADR(targetVariable);
   IF ComReceiveData = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ComReceiveData = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ComReceiveData^; // NULL 체크 없음!
value := ComReceiveData.member; // NULL 체크 없음!

✅ 안전: IF ComReceiveData <> NULL THEN
value := ComReceiveData^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ComReceiveData) THEN
value := ComReceiveData.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: SEQ_Driver_NGK_O2Analyzer: 192줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Driver_NGK_O2Analyzer = 192줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: step = 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(step - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF step >= (0 - 1.0E-6) AND
      step <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF step >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(step * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF step = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(step - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: StringReceived = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(StringReceived - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF StringReceived >= (TRUE - 1.0E-6) AND
      StringReceived <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF StringReceived >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(StringReceived * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF StringReceived = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(StringReceived - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: StringReceived = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(StringReceived - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF StringReceived >= (TRUE - 1.0E-6) AND
      StringReceived <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF StringReceived >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(StringReceived * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF StringReceived = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(StringReceived - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: ARRAY[0..2]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 0..2 >= 1 AND
      0..2 <= 10 THEN
       value := ARRAY[0..2];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 0..2, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 0..2 >= ARRAY_MIN AND 0..2 <= ARRAY_MAX THEN
       value := ARRAY[0..2];
   END_IF

예시:

❌ 위험: value := ARRAY[0..2]; // 범위 검사 없음!

✅ 안전: IF 0..2 >= 1 AND 0..2 <= 10 THEN
value := ARRAY[0..2];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: 206000: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 206000 <> NULL THEN
       value := 206000^;
       // 또는 206000.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 206000');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(206000) THEN
       value := 206000.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   206000 := ADR(targetVariable);
   IF 206000 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 206000 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 206000^; // NULL 체크 없음!
value := 206000.member; // NULL 체크 없음!

✅ 안전: IF 206000 <> NULL THEN
value := 206000^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(206000) THEN
value := 206000.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: 20: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 20 <> NULL THEN
       value := 20^;
       // 또는 20.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 20');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(20) THEN
       value := 20.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   20 := ADR(targetVariable);
   IF 20 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 20 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 20^; // NULL 체크 없음!
value := 20.member; // NULL 체크 없음!

✅ 안전: IF 20 <> NULL THEN
value := 20^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(20) THEN
value := 20.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: 1000000: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 1000000 <> NULL THEN
       value := 1000000^;
       // 또는 1000000.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 1000000');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(1000000) THEN
       value := 1000000.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   1000000 := ADR(targetVariable);
   IF 1000000 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 1000000 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 1000000^; // NULL 체크 없음!
value := 1000000.member; // NULL 체크 없음!

✅ 안전: IF 1000000 <> NULL THEN
value := 1000000^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(1000000) THEN
value := 1000000.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: 100: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 100 <> NULL THEN
       value := 100^;
       // 또는 100.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 100');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(100) THEN
       value := 100.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   100 := ADR(targetVariable);
   IF 100 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 100 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 100^; // NULL 체크 없음!
value := 100.member; // NULL 체크 없음!

✅ 안전: IF 100 <> NULL THEN
value := 100^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(100) THEN
value := 100.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: 100: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 100 <> NULL THEN
       value := 100^;
       // 또는 100.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 100');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(100) THEN
       value := 100.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   100 := ADR(targetVariable);
   IF 100 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 100 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 100^; // NULL 체크 없음!
value := 100.member; // NULL 체크 없음!

✅ 안전: IF 100 <> NULL THEN
value := 100^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(100) THEN
value := 100.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: TimeOut: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF TimeOut <> NULL THEN
       value := TimeOut^;
       // 또는 TimeOut.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: TimeOut');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(TimeOut) THEN
       value := TimeOut.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   TimeOut := ADR(targetVariable);
   IF TimeOut = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF TimeOut = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := TimeOut^; // NULL 체크 없음!
value := TimeOut.member; // NULL 체크 없음!

✅ 안전: IF TimeOut <> NULL THEN
value := TimeOut^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(TimeOut) THEN
value := TimeOut.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: tConnect: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF tConnect <> NULL THEN
       value := tConnect^;
       // 또는 tConnect.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: tConnect');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(tConnect) THEN
       value := tConnect.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   tConnect := ADR(targetVariable);
   IF tConnect = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF tConnect = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := tConnect^; // NULL 체크 없음!
value := tConnect.member; // NULL 체크 없음!

✅ 안전: IF tConnect <> NULL THEN
value := tConnect^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(tConnect) THEN
value := tConnect.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: eDesc_O2AnalyzerMaker: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_O2AnalyzerMaker <> NULL THEN
       value := eDesc_O2AnalyzerMaker^;
       // 또는 eDesc_O2AnalyzerMaker.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_O2AnalyzerMaker');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_O2AnalyzerMaker) THEN
       value := eDesc_O2AnalyzerMaker.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_O2AnalyzerMaker := ADR(targetVariable);
   IF eDesc_O2AnalyzerMaker = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_O2AnalyzerMaker = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_O2AnalyzerMaker^; // NULL 체크 없음!
value := eDesc_O2AnalyzerMaker.member; // NULL 체크 없음!

✅ 안전: IF eDesc_O2AnalyzerMaker <> NULL THEN
value := eDesc_O2AnalyzerMaker^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_O2AnalyzerMaker) THEN
value := eDesc_O2AnalyzerMaker.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: eDesc_O2AnalyzerMaker: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_O2AnalyzerMaker <> NULL THEN
       value := eDesc_O2AnalyzerMaker^;
       // 또는 eDesc_O2AnalyzerMaker.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_O2AnalyzerMaker');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_O2AnalyzerMaker) THEN
       value := eDesc_O2AnalyzerMaker.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_O2AnalyzerMaker := ADR(targetVariable);
   IF eDesc_O2AnalyzerMaker = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_O2AnalyzerMaker = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_O2AnalyzerMaker^; // NULL 체크 없음!
value := eDesc_O2AnalyzerMaker.member; // NULL 체크 없음!

✅ 안전: IF eDesc_O2AnalyzerMaker <> NULL THEN
value := eDesc_O2AnalyzerMaker^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_O2AnalyzerMaker) THEN
value := eDesc_O2AnalyzerMaker.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: eDesc_Autocal_Type: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_Autocal_Type <> NULL THEN
       value := eDesc_Autocal_Type^;
       // 또는 eDesc_Autocal_Type.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_Autocal_Type');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_Autocal_Type) THEN
       value := eDesc_Autocal_Type.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_Autocal_Type := ADR(targetVariable);
   IF eDesc_Autocal_Type = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_Autocal_Type = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_Autocal_Type^; // NULL 체크 없음!
value := eDesc_Autocal_Type.member; // NULL 체크 없음!

✅ 안전: IF eDesc_Autocal_Type <> NULL THEN
value := eDesc_Autocal_Type^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_Autocal_Type) THEN
value := eDesc_Autocal_Type.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: eDesc_Autocal_Type: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_Autocal_Type <> NULL THEN
       value := eDesc_Autocal_Type^;
       // 또는 eDesc_Autocal_Type.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_Autocal_Type');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_Autocal_Type) THEN
       value := eDesc_Autocal_Type.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_Autocal_Type := ADR(targetVariable);
   IF eDesc_Autocal_Type = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_Autocal_Type = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_Autocal_Type^; // NULL 체크 없음!
value := eDesc_Autocal_Type.member; // NULL 체크 없음!

✅ 안전: IF eDesc_Autocal_Type <> NULL THEN
value := eDesc_Autocal_Type^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_Autocal_Type) THEN
value := eDesc_Autocal_Type.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: eDesc_O2AnalyzerMaker: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_O2AnalyzerMaker <> NULL THEN
       value := eDesc_O2AnalyzerMaker^;
       // 또는 eDesc_O2AnalyzerMaker.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_O2AnalyzerMaker');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_O2AnalyzerMaker) THEN
       value := eDesc_O2AnalyzerMaker.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_O2AnalyzerMaker := ADR(targetVariable);
   IF eDesc_O2AnalyzerMaker = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_O2AnalyzerMaker = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_O2AnalyzerMaker^; // NULL 체크 없음!
value := eDesc_O2AnalyzerMaker.member; // NULL 체크 없음!

✅ 안전: IF eDesc_O2AnalyzerMaker <> NULL THEN
value := eDesc_O2AnalyzerMaker^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_O2AnalyzerMaker) THEN
value := eDesc_O2AnalyzerMaker.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: Delay_Time: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Delay_Time <> NULL THEN
       value := Delay_Time^;
       // 또는 Delay_Time.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Delay_Time');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Delay_Time) THEN
       value := Delay_Time.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Delay_Time := ADR(targetVariable);
   IF Delay_Time = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Delay_Time = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Delay_Time^; // NULL 체크 없음!
value := Delay_Time.member; // NULL 체크 없음!

✅ 안전: IF Delay_Time <> NULL THEN
value := Delay_Time^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Delay_Time) THEN
value := Delay_Time.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: ComReceiveData: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ComReceiveData <> NULL THEN
       value := ComReceiveData^;
       // 또는 ComReceiveData.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ComReceiveData');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ComReceiveData) THEN
       value := ComReceiveData.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ComReceiveData := ADR(targetVariable);
   IF ComReceiveData = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ComReceiveData = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ComReceiveData^; // NULL 체크 없음!
value := ComReceiveData.member; // NULL 체크 없음!

✅ 안전: IF ComReceiveData <> NULL THEN
value := ComReceiveData^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ComReceiveData) THEN
value := ComReceiveData.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: ComReceiveData: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ComReceiveData <> NULL THEN
       value := ComReceiveData^;
       // 또는 ComReceiveData.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ComReceiveData');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ComReceiveData) THEN
       value := ComReceiveData.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ComReceiveData := ADR(targetVariable);
   IF ComReceiveData = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ComReceiveData = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ComReceiveData^; // NULL 체크 없음!
value := ComReceiveData.member; // NULL 체크 없음!

✅ 안전: IF ComReceiveData <> NULL THEN
value := ComReceiveData^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ComReceiveData) THEN
value := ComReceiveData.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: SEQ_Driver_O2Analyzer: 804줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Driver_O2Analyzer = 804줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: DX_CFG_O2Analyzer_Maker = eDesc_O2AnalyzerMaker.eZirox: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_CFG_O2Analyzer_Maker - eDesc_O2AnalyzerMaker.eZirox) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_CFG_O2Analyzer_Maker >= (eDesc_O2AnalyzerMaker.eZirox - 1.0E-6) AND
      DX_CFG_O2Analyzer_Maker <= (eDesc_O2AnalyzerMaker.eZirox + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_CFG_O2Analyzer_Maker >= eDesc_O2AnalyzerMaker.eZirox THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_CFG_O2Analyzer_Maker * 10.0);
   intTarget := REAL_TO_DINT(eDesc_O2AnalyzerMaker.eZirox * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_CFG_O2Analyzer_Maker = eDesc_O2AnalyzerMaker.eZirox THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_CFG_O2Analyzer_Maker - eDesc_O2AnalyzerMaker.eZirox) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: step = 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(step - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF step >= (0 - 1.0E-6) AND
      step <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF step >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(step * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF step = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(step - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: DO_O2_CAL_Command = eO2_Cal_Set: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DO_O2_CAL_Command - eO2_Cal_Set) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DO_O2_CAL_Command >= (eO2_Cal_Set - 1.0E-6) AND
      DO_O2_CAL_Command <= (eO2_Cal_Set + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DO_O2_CAL_Command >= eO2_Cal_Set THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DO_O2_CAL_Command * 10.0);
   intTarget := REAL_TO_DINT(eO2_Cal_Set * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DO_O2_CAL_Command = eO2_Cal_Set THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DO_O2_CAL_Command - eO2_Cal_Set) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: DX_INF_State_Process <> eProcess_Processing: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Process >= (eProcess_Processing - 1.0E-6) AND
      DX_INF_State_Process <= (eProcess_Processing + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Process >= eProcess_Processing THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Process * 10.0);
   intTarget := REAL_TO_DINT(eProcess_Processing * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Process = eProcess_Processing THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: StringReceived = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(StringReceived - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF StringReceived >= (TRUE - 1.0E-6) AND
      StringReceived <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF StringReceived >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(StringReceived * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF StringReceived = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(StringReceived - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: ARRAY[0..2]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 0..2 >= 1 AND
      0..2 <= 10 THEN
       value := ARRAY[0..2];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 0..2, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 0..2 >= ARRAY_MIN AND 0..2 <= ARRAY_MAX THEN
       value := ARRAY[0..2];
   END_IF

예시:

❌ 위험: value := ARRAY[0..2]; // 범위 검사 없음!

✅ 안전: IF 0..2 >= 1 AND 0..2 <= 10 THEN
value := ARRAY[0..2];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: Timeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timeout <> NULL THEN
       value := Timeout^;
       // 또는 Timeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timeout) THEN
       value := Timeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timeout := ADR(targetVariable);
   IF Timeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timeout^; // NULL 체크 없음!
value := Timeout.member; // NULL 체크 없음!

✅ 안전: IF Timeout <> NULL THEN
value := Timeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timeout) THEN
value := Timeout.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: eIndex_MFC: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eIndex_MFC <> NULL THEN
       value := eIndex_MFC^;
       // 또는 eIndex_MFC.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eIndex_MFC');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eIndex_MFC) THEN
       value := eIndex_MFC.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eIndex_MFC := ADR(targetVariable);
   IF eIndex_MFC = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eIndex_MFC = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eIndex_MFC^; // NULL 체크 없음!
value := eIndex_MFC.member; // NULL 체크 없음!

✅ 안전: IF eIndex_MFC <> NULL THEN
value := eIndex_MFC^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eIndex_MFC) THEN
value := eIndex_MFC.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: 3: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 3 <> NULL THEN
       value := 3^;
       // 또는 3.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 3');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(3) THEN
       value := 3.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   3 := ADR(targetVariable);
   IF 3 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 3 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 3^; // NULL 체크 없음!
value := 3.member; // NULL 체크 없음!

✅ 안전: IF 3 <> NULL THEN
value := 3^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(3) THEN
value := 3.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: 5: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 5 <> NULL THEN
       value := 5^;
       // 또는 5.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 5');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(5) THEN
       value := 5.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   5 := ADR(targetVariable);
   IF 5 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 5 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 5^; // NULL 체크 없음!
value := 5.member; // NULL 체크 없음!

✅ 안전: IF 5 <> NULL THEN
value := 5^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(5) THEN
value := 5.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: 3: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 3 <> NULL THEN
       value := 3^;
       // 또는 3.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 3');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(3) THEN
       value := 3.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   3 := ADR(targetVariable);
   IF 3 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 3 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 3^; // NULL 체크 없음!
value := 3.member; // NULL 체크 없음!

✅ 안전: IF 3 <> NULL THEN
value := 3^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(3) THEN
value := 3.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: 5: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 5 <> NULL THEN
       value := 5^;
       // 또는 5.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 5');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(5) THEN
       value := 5.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   5 := ADR(targetVariable);
   IF 5 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 5 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 5^; // NULL 체크 없음!
value := 5.member; // NULL 체크 없음!

✅ 안전: IF 5 <> NULL THEN
value := 5^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(5) THEN
value := 5.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: SEQ_Driver_SdoMfc: 213줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Driver_SdoMfc = 213줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: Mode = eSdoMfc_GLIFE_INIT: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eSdoMfc_GLIFE_INIT) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eSdoMfc_GLIFE_INIT - 1.0E-6) AND
      Mode <= (eSdoMfc_GLIFE_INIT + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eSdoMfc_GLIFE_INIT THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eSdoMfc_GLIFE_INIT * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eSdoMfc_GLIFE_INIT THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eSdoMfc_GLIFE_INIT) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: ARRAY[1..cMAX_G_LIFE_Gas]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_G_LIFE_Gas >= 1 AND
      1..cMAX_G_LIFE_Gas <= 10 THEN
       value := ARRAY[1..cMAX_G_LIFE_Gas];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_G_LIFE_Gas, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_G_LIFE_Gas >= ARRAY_MIN AND 1..cMAX_G_LIFE_Gas <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_G_LIFE_Gas];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_G_LIFE_Gas]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_G_LIFE_Gas >= 1 AND 1..cMAX_G_LIFE_Gas <= 10 THEN
value := ARRAY[1..cMAX_G_LIFE_Gas];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: ARRAY[1..cMAX_G_LIFE_Para]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_G_LIFE_Para >= 1 AND
      1..cMAX_G_LIFE_Para <= 10 THEN
       value := ARRAY[1..cMAX_G_LIFE_Para];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_G_LIFE_Para, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_G_LIFE_Para >= ARRAY_MIN AND 1..cMAX_G_LIFE_Para <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_G_LIFE_Para];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_G_LIFE_Para]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_G_LIFE_Para >= 1 AND 1..cMAX_G_LIFE_Para <= 10 THEN
value := ARRAY[1..cMAX_G_LIFE_Para];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: ARRAY[1..cMAX_G_LIFE_Para]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_G_LIFE_Para >= 1 AND
      1..cMAX_G_LIFE_Para <= 10 THEN
       value := ARRAY[1..cMAX_G_LIFE_Para];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_G_LIFE_Para, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_G_LIFE_Para >= ARRAY_MIN AND 1..cMAX_G_LIFE_Para <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_G_LIFE_Para];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_G_LIFE_Para]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_G_LIFE_Para >= 1 AND 1..cMAX_G_LIFE_Para <= 10 THEN
value := ARRAY[1..cMAX_G_LIFE_Para];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF REAL_TO_INT(AO_G_LIFE_Target) >= 1 AND
      REAL_TO_INT(AO_G_LIFE_Target) <= 10 THEN
       value := DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, REAL_TO_INT(AO_G_LIFE_Target), 10);
   value := DX_MFC_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF REAL_TO_INT(AO_G_LIFE_Target) >= ARRAY_MIN AND REAL_TO_INT(AO_G_LIFE_Target) <= ARRAY_MAX THEN
       value := DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)];
   END_IF

예시:

❌ 위험: value := DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)]; // 범위 검사 없음!

✅ 안전: IF REAL_TO_INT(AO_G_LIFE_Target) >= 1 AND REAL_TO_INT(AO_G_LIFE_Target) <= 10 THEN
value := DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF REAL_TO_INT(AO_G_LIFE_Target) >= 1 AND
      REAL_TO_INT(AO_G_LIFE_Target) <= 10 THEN
       value := DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, REAL_TO_INT(AO_G_LIFE_Target), 10);
   value := DX_MFC_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF REAL_TO_INT(AO_G_LIFE_Target) >= ARRAY_MIN AND REAL_TO_INT(AO_G_LIFE_Target) <= ARRAY_MAX THEN
       value := DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)];
   END_IF

예시:

❌ 위험: value := DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)]; // 범위 검사 없음!

✅ 안전: IF REAL_TO_INT(AO_G_LIFE_Target) >= 1 AND REAL_TO_INT(AO_G_LIFE_Target) <= 10 THEN
value := DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF REAL_TO_INT(AO_G_LIFE_Target) >= 1 AND
      REAL_TO_INT(AO_G_LIFE_Target) <= 10 THEN
       value := DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, REAL_TO_INT(AO_G_LIFE_Target), 10);
   value := DX_MFC_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF REAL_TO_INT(AO_G_LIFE_Target) >= ARRAY_MIN AND REAL_TO_INT(AO_G_LIFE_Target) <= ARRAY_MAX THEN
       value := DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)];
   END_IF

예시:

❌ 위험: value := DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)]; // 범위 검사 없음!

✅ 안전: IF REAL_TO_INT(AO_G_LIFE_Target) >= 1 AND REAL_TO_INT(AO_G_LIFE_Target) <= 10 THEN
value := DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF REAL_TO_INT(AO_G_LIFE_Target) >= 1 AND
      REAL_TO_INT(AO_G_LIFE_Target) <= 10 THEN
       value := DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, REAL_TO_INT(AO_G_LIFE_Target), 10);
   value := DX_MFC_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF REAL_TO_INT(AO_G_LIFE_Target) >= ARRAY_MIN AND REAL_TO_INT(AO_G_LIFE_Target) <= ARRAY_MAX THEN
       value := DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)];
   END_IF

예시:

❌ 위험: value := DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)]; // 범위 검사 없음!

✅ 안전: IF REAL_TO_INT(AO_G_LIFE_Target) >= 1 AND REAL_TO_INT(AO_G_LIFE_Target) <= 10 THEN
value := DX_MFC_Mode[REAL_TO_INT(AO_G_LIFE_Target)];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: AO_MFC_SET[REAL_TO_INT(AO_G_LIFE_Target)]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF REAL_TO_INT(AO_G_LIFE_Target) >= 1 AND
      REAL_TO_INT(AO_G_LIFE_Target) <= 10 THEN
       value := AO_MFC_SET[REAL_TO_INT(AO_G_LIFE_Target)];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, REAL_TO_INT(AO_G_LIFE_Target), 10);
   value := AO_MFC_SET[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF REAL_TO_INT(AO_G_LIFE_Target) >= ARRAY_MIN AND REAL_TO_INT(AO_G_LIFE_Target) <= ARRAY_MAX THEN
       value := AO_MFC_SET[REAL_TO_INT(AO_G_LIFE_Target)];
   END_IF

예시:

❌ 위험: value := AO_MFC_SET[REAL_TO_INT(AO_G_LIFE_Target)]; // 범위 검사 없음!

✅ 안전: IF REAL_TO_INT(AO_G_LIFE_Target) >= 1 AND REAL_TO_INT(AO_G_LIFE_Target) <= 10 THEN
value := AO_MFC_SET[REAL_TO_INT(AO_G_LIFE_Target)];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: DX_CFG_Gas_Use[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := DX_CFG_Gas_Use[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := DX_CFG_Gas_Use[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := DX_CFG_Gas_Use[Loop];
   END_IF

예시:

❌ 위험: value := DX_CFG_Gas_Use[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := DX_CFG_Gas_Use[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: DX_CFG_MFC_G_Life_Use[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := DX_CFG_MFC_G_Life_Use[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := DX_CFG_MFC_G_Life_Use[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := DX_CFG_MFC_G_Life_Use[Loop];
   END_IF

예시:

❌ 위험: value := DX_CFG_MFC_G_Life_Use[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := DX_CFG_MFC_G_Life_Use[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: DX_MFC_Index_Num[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := DX_MFC_Index_Num[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := DX_MFC_Index_Num[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := DX_MFC_Index_Num[Loop];
   END_IF

예시:

❌ 위험: value := DX_MFC_Index_Num[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := DX_MFC_Index_Num[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: DX_MFC_Mode[iMfcIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iMfcIndex >= 1 AND
      iMfcIndex <= 10 THEN
       value := DX_MFC_Mode[iMfcIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iMfcIndex, 10);
   value := DX_MFC_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iMfcIndex >= ARRAY_MIN AND iMfcIndex <= ARRAY_MAX THEN
       value := DX_MFC_Mode[iMfcIndex];
   END_IF

예시:

❌ 위험: value := DX_MFC_Mode[iMfcIndex]; // 범위 검사 없음!

✅ 안전: IF iMfcIndex >= 1 AND iMfcIndex <= 10 THEN
value := DX_MFC_Mode[iMfcIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: gMFC_InletValve[iMfcIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iMfcIndex >= 1 AND
      iMfcIndex <= 10 THEN
       value := gMFC_InletValve[iMfcIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iMfcIndex, 10);
   value := gMFC_InletValve[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iMfcIndex >= ARRAY_MIN AND iMfcIndex <= ARRAY_MAX THEN
       value := gMFC_InletValve[iMfcIndex];
   END_IF

예시:

❌ 위험: value := gMFC_InletValve[iMfcIndex]; // 범위 검사 없음!

✅ 안전: IF iMfcIndex >= 1 AND iMfcIndex <= 10 THEN
value := gMFC_InletValve[iMfcIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: DX_MFC_Mode[iMfcIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iMfcIndex >= 1 AND
      iMfcIndex <= 10 THEN
       value := DX_MFC_Mode[iMfcIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iMfcIndex, 10);
   value := DX_MFC_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iMfcIndex >= ARRAY_MIN AND iMfcIndex <= ARRAY_MAX THEN
       value := DX_MFC_Mode[iMfcIndex];
   END_IF

예시:

❌ 위험: value := DX_MFC_Mode[iMfcIndex]; // 범위 검사 없음!

✅ 안전: IF iMfcIndex >= 1 AND iMfcIndex <= 10 THEN
value := DX_MFC_Mode[iMfcIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: AO_MFC_Set[iMfcIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iMfcIndex >= 1 AND
      iMfcIndex <= 10 THEN
       value := AO_MFC_Set[iMfcIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iMfcIndex, 10);
   value := AO_MFC_Set[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iMfcIndex >= ARRAY_MIN AND iMfcIndex <= ARRAY_MAX THEN
       value := AO_MFC_Set[iMfcIndex];
   END_IF

예시:

❌ 위험: value := AO_MFC_Set[iMfcIndex]; // 범위 검사 없음!

✅ 안전: IF iMfcIndex >= 1 AND iMfcIndex <= 10 THEN
value := AO_MFC_Set[iMfcIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: fbAlarm[13001 + (iMfcIndex - 1) * 10 + 5]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 13001 + (iMfcIndex - 1) * 10 + 5 >= 1 AND
      13001 + (iMfcIndex - 1) * 10 + 5 <= 10 THEN
       value := fbAlarm[13001 + (iMfcIndex - 1) * 10 + 5];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 13001 + (iMfcIndex - 1) * 10 + 5, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 13001 + (iMfcIndex - 1) * 10 + 5 >= ARRAY_MIN AND 13001 + (iMfcIndex - 1) * 10 + 5 <= ARRAY_MAX THEN
       value := fbAlarm[13001 + (iMfcIndex - 1) * 10 + 5];
   END_IF

예시:

❌ 위험: value := fbAlarm[13001 + (iMfcIndex - 1) * 10 + 5]; // 범위 검사 없음!

✅ 안전: IF 13001 + (iMfcIndex - 1) * 10 + 5 >= 1 AND 13001 + (iMfcIndex - 1) * 10 + 5 <= 10 THEN
value := fbAlarm[13001 + (iMfcIndex - 1) * 10 + 5];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: fbSdoMfc[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := fbSdoMfc[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := fbSdoMfc[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := fbSdoMfc[Loop];
   END_IF

예시:

❌ 위험: value := fbSdoMfc[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := fbSdoMfc[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: DX_MFC_Mode[iMfcIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iMfcIndex >= 1 AND
      iMfcIndex <= 10 THEN
       value := DX_MFC_Mode[iMfcIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iMfcIndex, 10);
   value := DX_MFC_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iMfcIndex >= ARRAY_MIN AND iMfcIndex <= ARRAY_MAX THEN
       value := DX_MFC_Mode[iMfcIndex];
   END_IF

예시:

❌ 위험: value := DX_MFC_Mode[iMfcIndex]; // 범위 검사 없음!

✅ 안전: IF iMfcIndex >= 1 AND iMfcIndex <= 10 THEN
value := DX_MFC_Mode[iMfcIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: DX_CFG_MFC_G_Life_Use[iMfcIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iMfcIndex >= 1 AND
      iMfcIndex <= 10 THEN
       value := DX_CFG_MFC_G_Life_Use[iMfcIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iMfcIndex, 10);
   value := DX_CFG_MFC_G_Life_Use[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iMfcIndex >= ARRAY_MIN AND iMfcIndex <= ARRAY_MAX THEN
       value := DX_CFG_MFC_G_Life_Use[iMfcIndex];
   END_IF

예시:

❌ 위험: value := DX_CFG_MFC_G_Life_Use[iMfcIndex]; // 범위 검사 없음!

✅ 안전: IF iMfcIndex >= 1 AND iMfcIndex <= 10 THEN
value := DX_CFG_MFC_G_Life_Use[iMfcIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: DX_MFC_Mode[iMfcIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iMfcIndex >= 1 AND
      iMfcIndex <= 10 THEN
       value := DX_MFC_Mode[iMfcIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iMfcIndex, 10);
   value := DX_MFC_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iMfcIndex >= ARRAY_MIN AND iMfcIndex <= ARRAY_MAX THEN
       value := DX_MFC_Mode[iMfcIndex];
   END_IF

예시:

❌ 위험: value := DX_MFC_Mode[iMfcIndex]; // 범위 검사 없음!

✅ 안전: IF iMfcIndex >= 1 AND iMfcIndex <= 10 THEN
value := DX_MFC_Mode[iMfcIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: DX_CFG_MFC_G_Life_Use[iMfcIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iMfcIndex >= 1 AND
      iMfcIndex <= 10 THEN
       value := DX_CFG_MFC_G_Life_Use[iMfcIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iMfcIndex, 10);
   value := DX_CFG_MFC_G_Life_Use[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iMfcIndex >= ARRAY_MIN AND iMfcIndex <= ARRAY_MAX THEN
       value := DX_CFG_MFC_G_Life_Use[iMfcIndex];
   END_IF

예시:

❌ 위험: value := DX_CFG_MFC_G_Life_Use[iMfcIndex]; // 범위 검사 없음!

✅ 안전: IF iMfcIndex >= 1 AND iMfcIndex <= 10 THEN
value := DX_CFG_MFC_G_Life_Use[iMfcIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: DX_MFC_Mode[iMfcIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iMfcIndex >= 1 AND
      iMfcIndex <= 10 THEN
       value := DX_MFC_Mode[iMfcIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iMfcIndex, 10);
   value := DX_MFC_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iMfcIndex >= ARRAY_MIN AND iMfcIndex <= ARRAY_MAX THEN
       value := DX_MFC_Mode[iMfcIndex];
   END_IF

예시:

❌ 위험: value := DX_MFC_Mode[iMfcIndex]; // 범위 검사 없음!

✅ 안전: IF iMfcIndex >= 1 AND iMfcIndex <= 10 THEN
value := DX_MFC_Mode[iMfcIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: AX_CFG_Gas_Scale[iMfcIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iMfcIndex >= 1 AND
      iMfcIndex <= 10 THEN
       value := AX_CFG_Gas_Scale[iMfcIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iMfcIndex, 10);
   value := AX_CFG_Gas_Scale[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iMfcIndex >= ARRAY_MIN AND iMfcIndex <= ARRAY_MAX THEN
       value := AX_CFG_Gas_Scale[iMfcIndex];
   END_IF

예시:

❌ 위험: value := AX_CFG_Gas_Scale[iMfcIndex]; // 범위 검사 없음!

✅ 안전: IF iMfcIndex >= 1 AND iMfcIndex <= 10 THEN
value := AX_CFG_Gas_Scale[iMfcIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: ioNetID_MFC[iMfcIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iMfcIndex >= 1 AND
      iMfcIndex <= 10 THEN
       value := ioNetID_MFC[iMfcIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iMfcIndex, 10);
   value := ioNetID_MFC[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iMfcIndex >= ARRAY_MIN AND iMfcIndex <= ARRAY_MAX THEN
       value := ioNetID_MFC[iMfcIndex];
   END_IF

예시:

❌ 위험: value := ioNetID_MFC[iMfcIndex]; // 범위 검사 없음!

✅ 안전: IF iMfcIndex >= 1 AND iMfcIndex <= 10 THEN
value := ioNetID_MFC[iMfcIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: MFC_Port_Addr[iMfcIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iMfcIndex >= 1 AND
      iMfcIndex <= 10 THEN
       value := MFC_Port_Addr[iMfcIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iMfcIndex, 10);
   value := MFC_Port_Addr[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iMfcIndex >= ARRAY_MIN AND iMfcIndex <= ARRAY_MAX THEN
       value := MFC_Port_Addr[iMfcIndex];
   END_IF

예시:

❌ 위험: value := MFC_Port_Addr[iMfcIndex]; // 범위 검사 없음!

✅ 안전: IF iMfcIndex >= 1 AND iMfcIndex <= 10 THEN
value := MFC_Port_Addr[iMfcIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: AI_MFC_FLOW[iMfcIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iMfcIndex >= 1 AND
      iMfcIndex <= 10 THEN
       value := AI_MFC_FLOW[iMfcIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iMfcIndex, 10);
   value := AI_MFC_FLOW[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iMfcIndex >= ARRAY_MIN AND iMfcIndex <= ARRAY_MAX THEN
       value := AI_MFC_FLOW[iMfcIndex];
   END_IF

예시:

❌ 위험: value := AI_MFC_FLOW[iMfcIndex]; // 범위 검사 없음!

✅ 안전: IF iMfcIndex >= 1 AND iMfcIndex <= 10 THEN
value := AI_MFC_FLOW[iMfcIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: DX_CFG_Gas_Unit[iMfcIndex]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iMfcIndex >= 1 AND
      iMfcIndex <= 10 THEN
       value := DX_CFG_Gas_Unit[iMfcIndex];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iMfcIndex, 10);
   value := DX_CFG_Gas_Unit[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iMfcIndex >= ARRAY_MIN AND iMfcIndex <= ARRAY_MAX THEN
       value := DX_CFG_Gas_Unit[iMfcIndex];
   END_IF

예시:

❌ 위험: value := DX_CFG_Gas_Unit[iMfcIndex]; // 범위 검사 없음!

✅ 안전: IF iMfcIndex >= 1 AND iMfcIndex <= 10 THEN
value := DX_CFG_Gas_Unit[iMfcIndex];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: fbAlarm[10010 + (iMfcIndex - 1) * 20 + 0]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 10010 + (iMfcIndex - 1) * 20 + 0 >= 1 AND
      10010 + (iMfcIndex - 1) * 20 + 0 <= 10 THEN
       value := fbAlarm[10010 + (iMfcIndex - 1) * 20 + 0];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 10010 + (iMfcIndex - 1) * 20 + 0, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 10010 + (iMfcIndex - 1) * 20 + 0 >= ARRAY_MIN AND 10010 + (iMfcIndex - 1) * 20 + 0 <= ARRAY_MAX THEN
       value := fbAlarm[10010 + (iMfcIndex - 1) * 20 + 0];
   END_IF

예시:

❌ 위험: value := fbAlarm[10010 + (iMfcIndex - 1) * 20 + 0]; // 범위 검사 없음!

✅ 안전: IF 10010 + (iMfcIndex - 1) * 20 + 0 >= 1 AND 10010 + (iMfcIndex - 1) * 20 + 0 <= 10 THEN
value := fbAlarm[10010 + (iMfcIndex - 1) * 20 + 0];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: fbAlarm[10010 + (iMfcIndex - 1) * 20 + 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 10010 + (iMfcIndex - 1) * 20 + 1 >= 1 AND
      10010 + (iMfcIndex - 1) * 20 + 1 <= 10 THEN
       value := fbAlarm[10010 + (iMfcIndex - 1) * 20 + 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 10010 + (iMfcIndex - 1) * 20 + 1, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 10010 + (iMfcIndex - 1) * 20 + 1 >= ARRAY_MIN AND 10010 + (iMfcIndex - 1) * 20 + 1 <= ARRAY_MAX THEN
       value := fbAlarm[10010 + (iMfcIndex - 1) * 20 + 1];
   END_IF

예시:

❌ 위험: value := fbAlarm[10010 + (iMfcIndex - 1) * 20 + 1]; // 범위 검사 없음!

✅ 안전: IF 10010 + (iMfcIndex - 1) * 20 + 1 >= 1 AND 10010 + (iMfcIndex - 1) * 20 + 1 <= 10 THEN
value := fbAlarm[10010 + (iMfcIndex - 1) * 20 + 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:1

설명: SEQ_Driver_TCPIP: 2835줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Driver_TCPIP = 2835줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ioAI_ECAT_LPV_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAI_ECAT_LPV_POSITION <> NULL THEN
       value := ioAI_ECAT_LPV_POSITION^;
       // 또는 ioAI_ECAT_LPV_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAI_ECAT_LPV_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
       value := ioAI_ECAT_LPV_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAI_ECAT_LPV_POSITION := ADR(targetVariable);
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_LPV_POSITION^; // NULL 체크 없음!
value := ioAI_ECAT_LPV_POSITION.member; // NULL 체크 없음!

✅ 안전: IF ioAI_ECAT_LPV_POSITION <> NULL THEN
value := ioAI_ECAT_LPV_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
value := ioAI_ECAT_LPV_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ioAI_ECAT_LPV_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAI_ECAT_LPV_POSITION <> NULL THEN
       value := ioAI_ECAT_LPV_POSITION^;
       // 또는 ioAI_ECAT_LPV_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAI_ECAT_LPV_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
       value := ioAI_ECAT_LPV_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAI_ECAT_LPV_POSITION := ADR(targetVariable);
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_LPV_POSITION^; // NULL 체크 없음!
value := ioAI_ECAT_LPV_POSITION.member; // NULL 체크 없음!

✅ 안전: IF ioAI_ECAT_LPV_POSITION <> NULL THEN
value := ioAI_ECAT_LPV_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
value := ioAI_ECAT_LPV_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ioAI_ECAT_LPV_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAI_ECAT_LPV_POSITION <> NULL THEN
       value := ioAI_ECAT_LPV_POSITION^;
       // 또는 ioAI_ECAT_LPV_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAI_ECAT_LPV_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
       value := ioAI_ECAT_LPV_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAI_ECAT_LPV_POSITION := ADR(targetVariable);
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_LPV_POSITION^; // NULL 체크 없음!
value := ioAI_ECAT_LPV_POSITION.member; // NULL 체크 없음!

✅ 안전: IF ioAI_ECAT_LPV_POSITION <> NULL THEN
value := ioAI_ECAT_LPV_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
value := ioAI_ECAT_LPV_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ioAI_ECAT_LPV_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAI_ECAT_LPV_POSITION <> NULL THEN
       value := ioAI_ECAT_LPV_POSITION^;
       // 또는 ioAI_ECAT_LPV_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAI_ECAT_LPV_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
       value := ioAI_ECAT_LPV_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAI_ECAT_LPV_POSITION := ADR(targetVariable);
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_LPV_POSITION^; // NULL 체크 없음!
value := ioAI_ECAT_LPV_POSITION.member; // NULL 체크 없음!

✅ 안전: IF ioAI_ECAT_LPV_POSITION <> NULL THEN
value := ioAI_ECAT_LPV_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
value := ioAI_ECAT_LPV_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: IN_LPV_CURRENT_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF IN_LPV_CURRENT_POSITION <> NULL THEN
       value := IN_LPV_CURRENT_POSITION^;
       // 또는 IN_LPV_CURRENT_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: IN_LPV_CURRENT_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
       value := IN_LPV_CURRENT_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   IN_LPV_CURRENT_POSITION := ADR(targetVariable);
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := IN_LPV_CURRENT_POSITION^; // NULL 체크 없음!
value := IN_LPV_CURRENT_POSITION.member; // NULL 체크 없음!

✅ 안전: IF IN_LPV_CURRENT_POSITION <> NULL THEN
value := IN_LPV_CURRENT_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
value := IN_LPV_CURRENT_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ioAI_ECAT_LPV_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAI_ECAT_LPV_POSITION <> NULL THEN
       value := ioAI_ECAT_LPV_POSITION^;
       // 또는 ioAI_ECAT_LPV_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAI_ECAT_LPV_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
       value := ioAI_ECAT_LPV_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAI_ECAT_LPV_POSITION := ADR(targetVariable);
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_LPV_POSITION^; // NULL 체크 없음!
value := ioAI_ECAT_LPV_POSITION.member; // NULL 체크 없음!

✅ 안전: IF ioAI_ECAT_LPV_POSITION <> NULL THEN
value := ioAI_ECAT_LPV_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
value := ioAI_ECAT_LPV_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: IN_LPV_CURRENT_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF IN_LPV_CURRENT_POSITION <> NULL THEN
       value := IN_LPV_CURRENT_POSITION^;
       // 또는 IN_LPV_CURRENT_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: IN_LPV_CURRENT_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
       value := IN_LPV_CURRENT_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   IN_LPV_CURRENT_POSITION := ADR(targetVariable);
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := IN_LPV_CURRENT_POSITION^; // NULL 체크 없음!
value := IN_LPV_CURRENT_POSITION.member; // NULL 체크 없음!

✅ 안전: IF IN_LPV_CURRENT_POSITION <> NULL THEN
value := IN_LPV_CURRENT_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
value := IN_LPV_CURRENT_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ioAI_ECAT_LPV_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAI_ECAT_LPV_POSITION <> NULL THEN
       value := ioAI_ECAT_LPV_POSITION^;
       // 또는 ioAI_ECAT_LPV_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAI_ECAT_LPV_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
       value := ioAI_ECAT_LPV_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAI_ECAT_LPV_POSITION := ADR(targetVariable);
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_LPV_POSITION^; // NULL 체크 없음!
value := ioAI_ECAT_LPV_POSITION.member; // NULL 체크 없음!

✅ 안전: IF ioAI_ECAT_LPV_POSITION <> NULL THEN
value := ioAI_ECAT_LPV_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
value := ioAI_ECAT_LPV_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: IN_LPV_CURRENT_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF IN_LPV_CURRENT_POSITION <> NULL THEN
       value := IN_LPV_CURRENT_POSITION^;
       // 또는 IN_LPV_CURRENT_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: IN_LPV_CURRENT_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
       value := IN_LPV_CURRENT_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   IN_LPV_CURRENT_POSITION := ADR(targetVariable);
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := IN_LPV_CURRENT_POSITION^; // NULL 체크 없음!
value := IN_LPV_CURRENT_POSITION.member; // NULL 체크 없음!

✅ 안전: IF IN_LPV_CURRENT_POSITION <> NULL THEN
value := IN_LPV_CURRENT_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
value := IN_LPV_CURRENT_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ioAI_ECAT_LPV_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAI_ECAT_LPV_POSITION <> NULL THEN
       value := ioAI_ECAT_LPV_POSITION^;
       // 또는 ioAI_ECAT_LPV_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAI_ECAT_LPV_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
       value := ioAI_ECAT_LPV_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAI_ECAT_LPV_POSITION := ADR(targetVariable);
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_LPV_POSITION^; // NULL 체크 없음!
value := ioAI_ECAT_LPV_POSITION.member; // NULL 체크 없음!

✅ 안전: IF ioAI_ECAT_LPV_POSITION <> NULL THEN
value := ioAI_ECAT_LPV_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
value := ioAI_ECAT_LPV_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: IN_LPV_CURRENT_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF IN_LPV_CURRENT_POSITION <> NULL THEN
       value := IN_LPV_CURRENT_POSITION^;
       // 또는 IN_LPV_CURRENT_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: IN_LPV_CURRENT_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
       value := IN_LPV_CURRENT_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   IN_LPV_CURRENT_POSITION := ADR(targetVariable);
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := IN_LPV_CURRENT_POSITION^; // NULL 체크 없음!
value := IN_LPV_CURRENT_POSITION.member; // NULL 체크 없음!

✅ 안전: IF IN_LPV_CURRENT_POSITION <> NULL THEN
value := IN_LPV_CURRENT_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
value := IN_LPV_CURRENT_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ioAI_ECAT_LPV_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAI_ECAT_LPV_POSITION <> NULL THEN
       value := ioAI_ECAT_LPV_POSITION^;
       // 또는 ioAI_ECAT_LPV_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAI_ECAT_LPV_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
       value := ioAI_ECAT_LPV_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAI_ECAT_LPV_POSITION := ADR(targetVariable);
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_LPV_POSITION^; // NULL 체크 없음!
value := ioAI_ECAT_LPV_POSITION.member; // NULL 체크 없음!

✅ 안전: IF ioAI_ECAT_LPV_POSITION <> NULL THEN
value := ioAI_ECAT_LPV_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
value := ioAI_ECAT_LPV_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: IN_LPV_CURRENT_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF IN_LPV_CURRENT_POSITION <> NULL THEN
       value := IN_LPV_CURRENT_POSITION^;
       // 또는 IN_LPV_CURRENT_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: IN_LPV_CURRENT_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
       value := IN_LPV_CURRENT_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   IN_LPV_CURRENT_POSITION := ADR(targetVariable);
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := IN_LPV_CURRENT_POSITION^; // NULL 체크 없음!
value := IN_LPV_CURRENT_POSITION.member; // NULL 체크 없음!

✅ 안전: IF IN_LPV_CURRENT_POSITION <> NULL THEN
value := IN_LPV_CURRENT_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
value := IN_LPV_CURRENT_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ioAI_ECAT_LPV_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAI_ECAT_LPV_POSITION <> NULL THEN
       value := ioAI_ECAT_LPV_POSITION^;
       // 또는 ioAI_ECAT_LPV_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAI_ECAT_LPV_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
       value := ioAI_ECAT_LPV_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAI_ECAT_LPV_POSITION := ADR(targetVariable);
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_LPV_POSITION^; // NULL 체크 없음!
value := ioAI_ECAT_LPV_POSITION.member; // NULL 체크 없음!

✅ 안전: IF ioAI_ECAT_LPV_POSITION <> NULL THEN
value := ioAI_ECAT_LPV_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
value := ioAI_ECAT_LPV_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: IN_LPV_CURRENT_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF IN_LPV_CURRENT_POSITION <> NULL THEN
       value := IN_LPV_CURRENT_POSITION^;
       // 또는 IN_LPV_CURRENT_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: IN_LPV_CURRENT_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
       value := IN_LPV_CURRENT_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   IN_LPV_CURRENT_POSITION := ADR(targetVariable);
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := IN_LPV_CURRENT_POSITION^; // NULL 체크 없음!
value := IN_LPV_CURRENT_POSITION.member; // NULL 체크 없음!

✅ 안전: IF IN_LPV_CURRENT_POSITION <> NULL THEN
value := IN_LPV_CURRENT_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
value := IN_LPV_CURRENT_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ioAI_ECAT_LPV_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAI_ECAT_LPV_POSITION <> NULL THEN
       value := ioAI_ECAT_LPV_POSITION^;
       // 또는 ioAI_ECAT_LPV_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAI_ECAT_LPV_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
       value := ioAI_ECAT_LPV_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAI_ECAT_LPV_POSITION := ADR(targetVariable);
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_LPV_POSITION^; // NULL 체크 없음!
value := ioAI_ECAT_LPV_POSITION.member; // NULL 체크 없음!

✅ 안전: IF ioAI_ECAT_LPV_POSITION <> NULL THEN
value := ioAI_ECAT_LPV_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
value := ioAI_ECAT_LPV_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: IN_LPV_CURRENT_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF IN_LPV_CURRENT_POSITION <> NULL THEN
       value := IN_LPV_CURRENT_POSITION^;
       // 또는 IN_LPV_CURRENT_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: IN_LPV_CURRENT_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
       value := IN_LPV_CURRENT_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   IN_LPV_CURRENT_POSITION := ADR(targetVariable);
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := IN_LPV_CURRENT_POSITION^; // NULL 체크 없음!
value := IN_LPV_CURRENT_POSITION.member; // NULL 체크 없음!

✅ 안전: IF IN_LPV_CURRENT_POSITION <> NULL THEN
value := IN_LPV_CURRENT_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
value := IN_LPV_CURRENT_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ioAI_ECAT_LPV_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAI_ECAT_LPV_POSITION <> NULL THEN
       value := ioAI_ECAT_LPV_POSITION^;
       // 또는 ioAI_ECAT_LPV_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAI_ECAT_LPV_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
       value := ioAI_ECAT_LPV_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAI_ECAT_LPV_POSITION := ADR(targetVariable);
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_LPV_POSITION^; // NULL 체크 없음!
value := ioAI_ECAT_LPV_POSITION.member; // NULL 체크 없음!

✅ 안전: IF ioAI_ECAT_LPV_POSITION <> NULL THEN
value := ioAI_ECAT_LPV_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
value := ioAI_ECAT_LPV_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: IN_LPV_CURRENT_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF IN_LPV_CURRENT_POSITION <> NULL THEN
       value := IN_LPV_CURRENT_POSITION^;
       // 또는 IN_LPV_CURRENT_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: IN_LPV_CURRENT_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
       value := IN_LPV_CURRENT_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   IN_LPV_CURRENT_POSITION := ADR(targetVariable);
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := IN_LPV_CURRENT_POSITION^; // NULL 체크 없음!
value := IN_LPV_CURRENT_POSITION.member; // NULL 체크 없음!

✅ 안전: IF IN_LPV_CURRENT_POSITION <> NULL THEN
value := IN_LPV_CURRENT_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
value := IN_LPV_CURRENT_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ioAI_ECAT_LPV_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAI_ECAT_LPV_POSITION <> NULL THEN
       value := ioAI_ECAT_LPV_POSITION^;
       // 또는 ioAI_ECAT_LPV_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAI_ECAT_LPV_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
       value := ioAI_ECAT_LPV_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAI_ECAT_LPV_POSITION := ADR(targetVariable);
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_LPV_POSITION^; // NULL 체크 없음!
value := ioAI_ECAT_LPV_POSITION.member; // NULL 체크 없음!

✅ 안전: IF ioAI_ECAT_LPV_POSITION <> NULL THEN
value := ioAI_ECAT_LPV_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
value := ioAI_ECAT_LPV_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: IN_LPV_CURRENT_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF IN_LPV_CURRENT_POSITION <> NULL THEN
       value := IN_LPV_CURRENT_POSITION^;
       // 또는 IN_LPV_CURRENT_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: IN_LPV_CURRENT_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
       value := IN_LPV_CURRENT_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   IN_LPV_CURRENT_POSITION := ADR(targetVariable);
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := IN_LPV_CURRENT_POSITION^; // NULL 체크 없음!
value := IN_LPV_CURRENT_POSITION.member; // NULL 체크 없음!

✅ 안전: IF IN_LPV_CURRENT_POSITION <> NULL THEN
value := IN_LPV_CURRENT_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
value := IN_LPV_CURRENT_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ioAI_ECAT_LPV_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAI_ECAT_LPV_POSITION <> NULL THEN
       value := ioAI_ECAT_LPV_POSITION^;
       // 또는 ioAI_ECAT_LPV_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAI_ECAT_LPV_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
       value := ioAI_ECAT_LPV_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAI_ECAT_LPV_POSITION := ADR(targetVariable);
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_LPV_POSITION^; // NULL 체크 없음!
value := ioAI_ECAT_LPV_POSITION.member; // NULL 체크 없음!

✅ 안전: IF ioAI_ECAT_LPV_POSITION <> NULL THEN
value := ioAI_ECAT_LPV_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
value := ioAI_ECAT_LPV_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: IN_LPV_CURRENT_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF IN_LPV_CURRENT_POSITION <> NULL THEN
       value := IN_LPV_CURRENT_POSITION^;
       // 또는 IN_LPV_CURRENT_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: IN_LPV_CURRENT_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
       value := IN_LPV_CURRENT_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   IN_LPV_CURRENT_POSITION := ADR(targetVariable);
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF IN_LPV_CURRENT_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := IN_LPV_CURRENT_POSITION^; // NULL 체크 없음!
value := IN_LPV_CURRENT_POSITION.member; // NULL 체크 없음!

✅ 안전: IF IN_LPV_CURRENT_POSITION <> NULL THEN
value := IN_LPV_CURRENT_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(IN_LPV_CURRENT_POSITION) THEN
value := IN_LPV_CURRENT_POSITION.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ioAI_ECAT_LPV_POSITION: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioAI_ECAT_LPV_POSITION <> NULL THEN
       value := ioAI_ECAT_LPV_POSITION^;
       // 또는 ioAI_ECAT_LPV_POSITION.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioAI_ECAT_LPV_POSITION');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
       value := ioAI_ECAT_LPV_POSITION.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioAI_ECAT_LPV_POSITION := ADR(targetVariable);
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioAI_ECAT_LPV_POSITION = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioAI_ECAT_LPV_POSITION^; // NULL 체크 없음!
value := ioAI_ECAT_LPV_POSITION.member; // NULL 체크 없음!

✅ 안전: IF ioAI_ECAT_LPV_POSITION <> NULL THEN
value := ioAI_ECAT_LPV_POSITION^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioAI_ECAT_LPV_POSITION) THEN
value := ioAI_ECAT_LPV_POSITION.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: SEQ_Driver_TVLPV: 296줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Driver_TVLPV = 296줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: Simulation = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Simulation - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Simulation >= (FALSE - 1.0E-6) AND
      Simulation <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Simulation >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Simulation * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Simulation = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Simulation - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: DI_TV_Local_Remote = 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_TV_Local_Remote - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_TV_Local_Remote >= (0 - 1.0E-6) AND
      DI_TV_Local_Remote <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_TV_Local_Remote >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_TV_Local_Remote * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_TV_Local_Remote = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_TV_Local_Remote - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ARRAY[1..48]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..48 >= 1 AND
      1..48 <= 10 THEN
       value := ARRAY[1..48];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..48, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..48 >= ARRAY_MIN AND 1..48 <= ARRAY_MAX THEN
       value := ARRAY[1..48];
   END_IF

예시:

❌ 위험: value := ARRAY[1..48]; // 범위 검사 없음!

✅ 안전: IF 1..48 >= 1 AND 1..48 <= 10 THEN
value := ARRAY[1..48];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ARRAY[1..cMAX_TV]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_TV >= 1 AND
      1..cMAX_TV <= 10 THEN
       value := ARRAY[1..cMAX_TV];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_TV, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_TV >= ARRAY_MIN AND 1..cMAX_TV <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_TV];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_TV]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_TV >= 1 AND 1..cMAX_TV <= 10 THEN
value := ARRAY[1..cMAX_TV];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ARRAY[1..cMAX_TV]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_TV >= 1 AND
      1..cMAX_TV <= 10 THEN
       value := ARRAY[1..cMAX_TV];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_TV, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_TV >= ARRAY_MIN AND 1..cMAX_TV <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_TV];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_TV]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_TV >= 1 AND 1..cMAX_TV <= 10 THEN
value := ARRAY[1..cMAX_TV];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ARRAY[1..cMAX_TV]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_TV >= 1 AND
      1..cMAX_TV <= 10 THEN
       value := ARRAY[1..cMAX_TV];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_TV, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_TV >= ARRAY_MIN AND 1..cMAX_TV <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_TV];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_TV]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_TV >= 1 AND 1..cMAX_TV <= 10 THEN
value := ARRAY[1..cMAX_TV];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: ARRAY[1..cMAX_TV]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_TV >= 1 AND
      1..cMAX_TV <= 10 THEN
       value := ARRAY[1..cMAX_TV];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_TV, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_TV >= ARRAY_MIN AND 1..cMAX_TV <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_TV];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_TV]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_TV >= 1 AND 1..cMAX_TV <= 10 THEN
value := ARRAY[1..cMAX_TV];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: DI_TV_Alarm_Open_Sensor[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DI_TV_Alarm_Open_Sensor[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DI_TV_Alarm_Open_Sensor[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DI_TV_Alarm_Open_Sensor[i];
   END_IF

예시:

❌ 위험: value := DI_TV_Alarm_Open_Sensor[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DI_TV_Alarm_Open_Sensor[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: fbAlarm[25811+i - 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 25811+i - 1 >= 1 AND
      25811+i - 1 <= 10 THEN
       value := fbAlarm[25811+i - 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 25811+i - 1, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 25811+i - 1 >= ARRAY_MIN AND 25811+i - 1 <= ARRAY_MAX THEN
       value := fbAlarm[25811+i - 1];
   END_IF

예시:

❌ 위험: value := fbAlarm[25811+i - 1]; // 범위 검사 없음!

✅ 안전: IF 25811+i - 1 >= 1 AND 25811+i - 1 <= 10 THEN
value := fbAlarm[25811+i - 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: DI_TV_Alarm_Position[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DI_TV_Alarm_Position[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DI_TV_Alarm_Position[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DI_TV_Alarm_Position[i];
   END_IF

예시:

❌ 위험: value := DI_TV_Alarm_Position[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DI_TV_Alarm_Position[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: fbAlarm[25821+i - 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 25821+i - 1 >= 1 AND
      25821+i - 1 <= 10 THEN
       value := fbAlarm[25821+i - 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 25821+i - 1, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 25821+i - 1 >= ARRAY_MIN AND 25821+i - 1 <= ARRAY_MAX THEN
       value := fbAlarm[25821+i - 1];
   END_IF

예시:

❌ 위험: value := fbAlarm[25821+i - 1]; // 범위 검사 없음!

✅ 안전: IF 25821+i - 1 >= 1 AND 25821+i - 1 <= 10 THEN
value := fbAlarm[25821+i - 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: DI_TV_Alarm_Init[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DI_TV_Alarm_Init[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DI_TV_Alarm_Init[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DI_TV_Alarm_Init[i];
   END_IF

예시:

❌ 위험: value := DI_TV_Alarm_Init[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DI_TV_Alarm_Init[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: fbAlarm[25831+i - 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 25831+i - 1 >= 1 AND
      25831+i - 1 <= 10 THEN
       value := fbAlarm[25831+i - 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 25831+i - 1, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 25831+i - 1 >= ARRAY_MIN AND 25831+i - 1 <= ARRAY_MAX THEN
       value := fbAlarm[25831+i - 1];
   END_IF

예시:

❌ 위험: value := fbAlarm[25831+i - 1]; // 범위 검사 없음!

✅ 안전: IF 25831+i - 1 >= 1 AND 25831+i - 1 <= 10 THEN
value := fbAlarm[25831+i - 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: DI_TV_Alarm_Communication[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DI_TV_Alarm_Communication[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DI_TV_Alarm_Communication[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DI_TV_Alarm_Communication[i];
   END_IF

예시:

❌ 위험: value := DI_TV_Alarm_Communication[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DI_TV_Alarm_Communication[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: fbAlarm[25841+i - 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 25841+i - 1 >= 1 AND
      25841+i - 1 <= 10 THEN
       value := fbAlarm[25841+i - 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 25841+i - 1, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 25841+i - 1 >= ARRAY_MIN AND 25841+i - 1 <= ARRAY_MAX THEN
       value := fbAlarm[25841+i - 1];
   END_IF

예시:

❌ 위험: value := fbAlarm[25841+i - 1]; // 범위 검사 없음!

✅ 안전: IF 25841+i - 1 >= 1 AND 25841+i - 1 <= 10 THEN
value := fbAlarm[25841+i - 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: TimeDelay: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF TimeDelay <> NULL THEN
       value := TimeDelay^;
       // 또는 TimeDelay.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: TimeDelay');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(TimeDelay) THEN
       value := TimeDelay.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   TimeDelay := ADR(targetVariable);
   IF TimeDelay = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF TimeDelay = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := TimeDelay^; // NULL 체크 없음!
value := TimeDelay.member; // NULL 체크 없음!

✅ 안전: IF TimeDelay <> NULL THEN
value := TimeDelay^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(TimeDelay) THEN
value := TimeDelay.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: TimeDelay: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF TimeDelay <> NULL THEN
       value := TimeDelay^;
       // 또는 TimeDelay.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: TimeDelay');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(TimeDelay) THEN
       value := TimeDelay.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   TimeDelay := ADR(targetVariable);
   IF TimeDelay = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF TimeDelay = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := TimeDelay^; // NULL 체크 없음!
value := TimeDelay.member; // NULL 체크 없음!

✅ 안전: IF TimeDelay <> NULL THEN
value := TimeDelay^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(TimeDelay) THEN
value := TimeDelay.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: TimeDelay: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF TimeDelay <> NULL THEN
       value := TimeDelay^;
       // 또는 TimeDelay.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: TimeDelay');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(TimeDelay) THEN
       value := TimeDelay.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   TimeDelay := ADR(targetVariable);
   IF TimeDelay = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF TimeDelay = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := TimeDelay^; // NULL 체크 없음!
value := TimeDelay.member; // NULL 체크 없음!

✅ 안전: IF TimeDelay <> NULL THEN
value := TimeDelay^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(TimeDelay) THEN
value := TimeDelay.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: TimeOut: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF TimeOut <> NULL THEN
       value := TimeOut^;
       // 또는 TimeOut.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: TimeOut');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(TimeOut) THEN
       value := TimeOut.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   TimeOut := ADR(targetVariable);
   IF TimeOut = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF TimeOut = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := TimeOut^; // NULL 체크 없음!
value := TimeOut.member; // NULL 체크 없음!

✅ 안전: IF TimeOut <> NULL THEN
value := TimeOut^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(TimeOut) THEN
value := TimeOut.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: SEQ_Driver_TV_VAT: 121줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Driver_TV_VAT = 121줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: Step <> 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Step - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Step >= (0 - 1.0E-6) AND
      Step <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Step >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Step * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Step = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Step - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: oldMode_T <> iMode: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(oldMode_T - iMode) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF oldMode_T >= (iMode - 1.0E-6) AND
      oldMode_T <= (iMode + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF oldMode_T >= iMode THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(oldMode_T * 10.0);
   intTarget := REAL_TO_DINT(iMode * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF oldMode_T = iMode THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(oldMode_T - iMode) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: iMode = edTV_VAT_Pressure: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iMode - edTV_VAT_Pressure) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iMode >= (edTV_VAT_Pressure - 1.0E-6) AND
      iMode <= (edTV_VAT_Pressure + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iMode >= edTV_VAT_Pressure THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iMode * 10.0);
   intTarget := REAL_TO_DINT(edTV_VAT_Pressure * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iMode = edTV_VAT_Pressure THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iMode - edTV_VAT_Pressure) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: oldPressure <> iPressure: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(oldPressure - iPressure) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF oldPressure >= (iPressure - 1.0E-6) AND
      oldPressure <= (iPressure + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF oldPressure >= iPressure THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(oldPressure * 10.0);
   intTarget := REAL_TO_DINT(iPressure * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF oldPressure = iPressure THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(oldPressure - iPressure) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: iMode = edTV_VAT_Pressure: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iMode - edTV_VAT_Pressure) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iMode >= (edTV_VAT_Pressure - 1.0E-6) AND
      iMode <= (edTV_VAT_Pressure + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iMode >= edTV_VAT_Pressure THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iMode * 10.0);
   intTarget := REAL_TO_DINT(edTV_VAT_Pressure * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iMode = edTV_VAT_Pressure THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iMode - edTV_VAT_Pressure) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: oldPosition <> iPosition: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(oldPosition - iPosition) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF oldPosition >= (iPosition - 1.0E-6) AND
      oldPosition <= (iPosition + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF oldPosition >= iPosition THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(oldPosition * 10.0);
   intTarget := REAL_TO_DINT(iPosition * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF oldPosition = iPosition THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(oldPosition - iPosition) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: iMode = edTV_VAT_Position: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iMode - edTV_VAT_Position) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iMode >= (edTV_VAT_Position - 1.0E-6) AND
      iMode <= (edTV_VAT_Position + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iMode >= edTV_VAT_Position THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iMode * 10.0);
   intTarget := REAL_TO_DINT(edTV_VAT_Position * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iMode = edTV_VAT_Position THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iMode - edTV_VAT_Position) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: oldMode_T <> iMode: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(oldMode_T - iMode) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF oldMode_T >= (iMode - 1.0E-6) AND
      oldMode_T <= (iMode + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF oldMode_T >= iMode THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(oldMode_T * 10.0);
   intTarget := REAL_TO_DINT(iMode * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF oldMode_T = iMode THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(oldMode_T - iMode) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: iMode = edTV_VAT_Position: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iMode - edTV_VAT_Position) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iMode >= (edTV_VAT_Position - 1.0E-6) AND
      iMode <= (edTV_VAT_Position + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iMode >= edTV_VAT_Position THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iMode * 10.0);
   intTarget := REAL_TO_DINT(edTV_VAT_Position * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iMode = edTV_VAT_Position THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iMode - edTV_VAT_Position) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: oldMode_T <> iMode: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(oldMode_T - iMode) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF oldMode_T >= (iMode - 1.0E-6) AND
      oldMode_T <= (iMode + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF oldMode_T >= iMode THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(oldMode_T * 10.0);
   intTarget := REAL_TO_DINT(iMode * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF oldMode_T = iMode THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(oldMode_T - iMode) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: iMode = edTV_VAT_Open: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iMode - edTV_VAT_Open) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iMode >= (edTV_VAT_Open - 1.0E-6) AND
      iMode <= (edTV_VAT_Open + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iMode >= edTV_VAT_Open THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iMode * 10.0);
   intTarget := REAL_TO_DINT(edTV_VAT_Open * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iMode = edTV_VAT_Open THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iMode - edTV_VAT_Open) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: iMode = edTV_VAT_Close: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iMode - edTV_VAT_Close) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iMode >= (edTV_VAT_Close - 1.0E-6) AND
      iMode <= (edTV_VAT_Close + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iMode >= edTV_VAT_Close THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iMode * 10.0);
   intTarget := REAL_TO_DINT(edTV_VAT_Close * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iMode = edTV_VAT_Close THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iMode - edTV_VAT_Close) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: iMode = edTV_VAT_Hold: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(iMode - edTV_VAT_Hold) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF iMode >= (edTV_VAT_Hold - 1.0E-6) AND
      iMode <= (edTV_VAT_Hold + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF iMode >= edTV_VAT_Hold THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(iMode * 10.0);
   intTarget := REAL_TO_DINT(edTV_VAT_Hold * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF iMode = edTV_VAT_Hold THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(iMode - edTV_VAT_Hold) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:1

설명: TimeOut: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF TimeOut <> NULL THEN
       value := TimeOut^;
       // 또는 TimeOut.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: TimeOut');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(TimeOut) THEN
       value := TimeOut.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   TimeOut := ADR(targetVariable);
   IF TimeOut = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF TimeOut = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := TimeOut^; // NULL 체크 없음!
value := TimeOut.member; // NULL 체크 없음!

✅ 안전: IF TimeOut <> NULL THEN
value := TimeOut^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(TimeOut) THEN
value := TimeOut.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:1

설명: tConnect: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF tConnect <> NULL THEN
       value := tConnect^;
       // 또는 tConnect.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: tConnect');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(tConnect) THEN
       value := tConnect.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   tConnect := ADR(targetVariable);
   IF tConnect = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF tConnect = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := tConnect^; // NULL 체크 없음!
value := tConnect.member; // NULL 체크 없음!

✅ 안전: IF tConnect <> NULL THEN
value := tConnect^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(tConnect) THEN
value := tConnect.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:1

설명: Delay_Time: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Delay_Time <> NULL THEN
       value := Delay_Time^;
       // 또는 Delay_Time.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Delay_Time');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Delay_Time) THEN
       value := Delay_Time.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Delay_Time := ADR(targetVariable);
   IF Delay_Time = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Delay_Time = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Delay_Time^; // NULL 체크 없음!
value := Delay_Time.member; // NULL 체크 없음!

✅ 안전: IF Delay_Time <> NULL THEN
value := Delay_Time^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Delay_Time) THEN
value := Delay_Time.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:1

설명: ComReceiveData: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ComReceiveData <> NULL THEN
       value := ComReceiveData^;
       // 또는 ComReceiveData.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ComReceiveData');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ComReceiveData) THEN
       value := ComReceiveData.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ComReceiveData := ADR(targetVariable);
   IF ComReceiveData = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ComReceiveData = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ComReceiveData^; // NULL 체크 없음!
value := ComReceiveData.member; // NULL 체크 없음!

✅ 안전: IF ComReceiveData <> NULL THEN
value := ComReceiveData^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ComReceiveData) THEN
value := ComReceiveData.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:1

설명: ComReceiveData: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ComReceiveData <> NULL THEN
       value := ComReceiveData^;
       // 또는 ComReceiveData.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ComReceiveData');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ComReceiveData) THEN
       value := ComReceiveData.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ComReceiveData := ADR(targetVariable);
   IF ComReceiveData = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ComReceiveData = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ComReceiveData^; // NULL 체크 없음!
value := ComReceiveData.member; // NULL 체크 없음!

✅ 안전: IF ComReceiveData <> NULL THEN
value := ComReceiveData^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ComReceiveData) THEN
value := ComReceiveData.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:1

설명: VAC_O2_Timer: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF VAC_O2_Timer <> NULL THEN
       value := VAC_O2_Timer^;
       // 또는 VAC_O2_Timer.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: VAC_O2_Timer');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(VAC_O2_Timer) THEN
       value := VAC_O2_Timer.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   VAC_O2_Timer := ADR(targetVariable);
   IF VAC_O2_Timer = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF VAC_O2_Timer = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := VAC_O2_Timer^; // NULL 체크 없음!
value := VAC_O2_Timer.member; // NULL 체크 없음!

✅ 안전: IF VAC_O2_Timer <> NULL THEN
value := VAC_O2_Timer^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(VAC_O2_Timer) THEN
value := VAC_O2_Timer.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:1

설명: Delay_Time: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Delay_Time <> NULL THEN
       value := Delay_Time^;
       // 또는 Delay_Time.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Delay_Time');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Delay_Time) THEN
       value := Delay_Time.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Delay_Time := ADR(targetVariable);
   IF Delay_Time = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Delay_Time = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Delay_Time^; // NULL 체크 없음!
value := Delay_Time.member; // NULL 체크 없음!

✅ 안전: IF Delay_Time <> NULL THEN
value := Delay_Time^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Delay_Time) THEN
value := Delay_Time.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:1

설명: Delay_Time: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Delay_Time <> NULL THEN
       value := Delay_Time^;
       // 또는 Delay_Time.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Delay_Time');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Delay_Time) THEN
       value := Delay_Time.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Delay_Time := ADR(targetVariable);
   IF Delay_Time = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Delay_Time = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Delay_Time^; // NULL 체크 없음!
value := Delay_Time.member; // NULL 체크 없음!

✅ 안전: IF Delay_Time <> NULL THEN
value := Delay_Time^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Delay_Time) THEN
value := Delay_Time.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:1

설명: SEQ_Driver_VAC_O2Analyzer: 274줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Driver_VAC_O2Analyzer = 274줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:1

설명: DX_CFG_VAC_O2_MonitorType = 1: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_CFG_VAC_O2_MonitorType - 1) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_CFG_VAC_O2_MonitorType >= (1 - 1.0E-6) AND
      DX_CFG_VAC_O2_MonitorType <= (1 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_CFG_VAC_O2_MonitorType >= 1 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_CFG_VAC_O2_MonitorType * 10.0);
   intTarget := REAL_TO_DINT(1 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_CFG_VAC_O2_MonitorType = 1 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_CFG_VAC_O2_MonitorType - 1) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:1

설명: step = 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(step - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF step >= (0 - 1.0E-6) AND
      step <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF step >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(step * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF step = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(step - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:1

설명: StringReceived = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(StringReceived - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF StringReceived >= (TRUE - 1.0E-6) AND
      StringReceived <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF StringReceived >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(StringReceived * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF StringReceived = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(StringReceived - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:1

설명: ARRAY[0..2]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 0..2 >= 1 AND
      0..2 <= 10 THEN
       value := ARRAY[0..2];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 0..2, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 0..2 >= ARRAY_MIN AND 0..2 <= ARRAY_MAX THEN
       value := ARRAY[0..2];
   END_IF

예시:

❌ 위험: value := ARRAY[0..2]; // 범위 검사 없음!

✅ 안전: IF 0..2 >= 1 AND 0..2 <= 10 THEN
value := ARRAY[0..2];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: 24: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 24 <> NULL THEN
       value := 24^;
       // 또는 24.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 24');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(24) THEN
       value := 24.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   24 := ADR(targetVariable);
   IF 24 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 24 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 24^; // NULL 체크 없음!
value := 24.member; // NULL 체크 없음!

✅ 안전: IF 24 <> NULL THEN
value := 24^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(24) THEN
value := 24.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: SEQ_Driver_VG: 142줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Driver_VG = 142줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: ioDI_ECAT_VG01_Reading_Valid = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioDI_ECAT_VG01_Reading_Valid - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioDI_ECAT_VG01_Reading_Valid >= (FALSE - 1.0E-6) AND
      ioDI_ECAT_VG01_Reading_Valid <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioDI_ECAT_VG01_Reading_Valid >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioDI_ECAT_VG01_Reading_Valid * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioDI_ECAT_VG01_Reading_Valid = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioDI_ECAT_VG01_Reading_Valid - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: ioDI_ECAT_VG01_Overrange_Exceeded = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioDI_ECAT_VG01_Overrange_Exceeded - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioDI_ECAT_VG01_Overrange_Exceeded >= (TRUE - 1.0E-6) AND
      ioDI_ECAT_VG01_Overrange_Exceeded <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioDI_ECAT_VG01_Overrange_Exceeded >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioDI_ECAT_VG01_Overrange_Exceeded * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioDI_ECAT_VG01_Overrange_Exceeded = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioDI_ECAT_VG01_Overrange_Exceeded - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: ioDI_ECAT_VG01_Underrange_Exceeded = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioDI_ECAT_VG01_Underrange_Exceeded - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioDI_ECAT_VG01_Underrange_Exceeded >= (TRUE - 1.0E-6) AND
      ioDI_ECAT_VG01_Underrange_Exceeded <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioDI_ECAT_VG01_Underrange_Exceeded >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioDI_ECAT_VG01_Underrange_Exceeded * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioDI_ECAT_VG01_Underrange_Exceeded = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioDI_ECAT_VG01_Underrange_Exceeded - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: ioDI_ECAT_VG02_Reading_Valid = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioDI_ECAT_VG02_Reading_Valid - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioDI_ECAT_VG02_Reading_Valid >= (FALSE - 1.0E-6) AND
      ioDI_ECAT_VG02_Reading_Valid <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioDI_ECAT_VG02_Reading_Valid >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioDI_ECAT_VG02_Reading_Valid * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioDI_ECAT_VG02_Reading_Valid = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioDI_ECAT_VG02_Reading_Valid - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: ioDI_ECAT_VG02_Overrange_Exceeded = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioDI_ECAT_VG02_Overrange_Exceeded - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioDI_ECAT_VG02_Overrange_Exceeded >= (TRUE - 1.0E-6) AND
      ioDI_ECAT_VG02_Overrange_Exceeded <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioDI_ECAT_VG02_Overrange_Exceeded >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioDI_ECAT_VG02_Overrange_Exceeded * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioDI_ECAT_VG02_Overrange_Exceeded = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioDI_ECAT_VG02_Overrange_Exceeded - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: ioDI_ECAT_VG02_Underrange_Exceeded = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioDI_ECAT_VG02_Underrange_Exceeded - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioDI_ECAT_VG02_Underrange_Exceeded >= (TRUE - 1.0E-6) AND
      ioDI_ECAT_VG02_Underrange_Exceeded <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioDI_ECAT_VG02_Underrange_Exceeded >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioDI_ECAT_VG02_Underrange_Exceeded * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioDI_ECAT_VG02_Underrange_Exceeded = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioDI_ECAT_VG02_Underrange_Exceeded - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: ioDI_ECAT_VG03_Reading_Valid = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioDI_ECAT_VG03_Reading_Valid - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioDI_ECAT_VG03_Reading_Valid >= (FALSE - 1.0E-6) AND
      ioDI_ECAT_VG03_Reading_Valid <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioDI_ECAT_VG03_Reading_Valid >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioDI_ECAT_VG03_Reading_Valid * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioDI_ECAT_VG03_Reading_Valid = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioDI_ECAT_VG03_Reading_Valid - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: ioDI_ECAT_VG03_Overrange_Exceeded = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioDI_ECAT_VG03_Overrange_Exceeded - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioDI_ECAT_VG03_Overrange_Exceeded >= (TRUE - 1.0E-6) AND
      ioDI_ECAT_VG03_Overrange_Exceeded <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioDI_ECAT_VG03_Overrange_Exceeded >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioDI_ECAT_VG03_Overrange_Exceeded * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioDI_ECAT_VG03_Overrange_Exceeded = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioDI_ECAT_VG03_Overrange_Exceeded - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: ioDI_ECAT_VG03_Underrange_Exceeded = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioDI_ECAT_VG03_Underrange_Exceeded - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioDI_ECAT_VG03_Underrange_Exceeded >= (TRUE - 1.0E-6) AND
      ioDI_ECAT_VG03_Underrange_Exceeded <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioDI_ECAT_VG03_Underrange_Exceeded >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioDI_ECAT_VG03_Underrange_Exceeded * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioDI_ECAT_VG03_Underrange_Exceeded = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioDI_ECAT_VG03_Underrange_Exceeded - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: ioDI_ECAT_VG04_Reading_Valid = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioDI_ECAT_VG04_Reading_Valid - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioDI_ECAT_VG04_Reading_Valid >= (FALSE - 1.0E-6) AND
      ioDI_ECAT_VG04_Reading_Valid <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioDI_ECAT_VG04_Reading_Valid >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioDI_ECAT_VG04_Reading_Valid * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioDI_ECAT_VG04_Reading_Valid = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioDI_ECAT_VG04_Reading_Valid - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: ioDI_ECAT_VG04_Overrange_Exceeded = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioDI_ECAT_VG04_Overrange_Exceeded - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioDI_ECAT_VG04_Overrange_Exceeded >= (TRUE - 1.0E-6) AND
      ioDI_ECAT_VG04_Overrange_Exceeded <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioDI_ECAT_VG04_Overrange_Exceeded >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioDI_ECAT_VG04_Overrange_Exceeded * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioDI_ECAT_VG04_Overrange_Exceeded = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioDI_ECAT_VG04_Overrange_Exceeded - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: ioDI_ECAT_VG04_Underrange_Exceeded = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioDI_ECAT_VG04_Underrange_Exceeded - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioDI_ECAT_VG04_Underrange_Exceeded >= (TRUE - 1.0E-6) AND
      ioDI_ECAT_VG04_Underrange_Exceeded <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioDI_ECAT_VG04_Underrange_Exceeded >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioDI_ECAT_VG04_Underrange_Exceeded * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioDI_ECAT_VG04_Underrange_Exceeded = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioDI_ECAT_VG04_Underrange_Exceeded - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: ioDI_ECAT_VG05_Reading_Valid = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioDI_ECAT_VG05_Reading_Valid - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioDI_ECAT_VG05_Reading_Valid >= (FALSE - 1.0E-6) AND
      ioDI_ECAT_VG05_Reading_Valid <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioDI_ECAT_VG05_Reading_Valid >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioDI_ECAT_VG05_Reading_Valid * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioDI_ECAT_VG05_Reading_Valid = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioDI_ECAT_VG05_Reading_Valid - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: ioDI_ECAT_VG05_Overrange_Exceeded = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioDI_ECAT_VG05_Overrange_Exceeded - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioDI_ECAT_VG05_Overrange_Exceeded >= (TRUE - 1.0E-6) AND
      ioDI_ECAT_VG05_Overrange_Exceeded <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioDI_ECAT_VG05_Overrange_Exceeded >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioDI_ECAT_VG05_Overrange_Exceeded * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioDI_ECAT_VG05_Overrange_Exceeded = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioDI_ECAT_VG05_Overrange_Exceeded - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: ioDI_ECAT_VG05_Underrange_Exceeded = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ioDI_ECAT_VG05_Underrange_Exceeded - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ioDI_ECAT_VG05_Underrange_Exceeded >= (TRUE - 1.0E-6) AND
      ioDI_ECAT_VG05_Underrange_Exceeded <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ioDI_ECAT_VG05_Underrange_Exceeded >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ioDI_ECAT_VG05_Underrange_Exceeded * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ioDI_ECAT_VG05_Underrange_Exceeded = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ioDI_ECAT_VG05_Underrange_Exceeded - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Delay_Start: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Delay_Start <> NULL THEN
       value := Delay_Start^;
       // 또는 Delay_Start.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Delay_Start');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Delay_Start) THEN
       value := Delay_Start.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Delay_Start := ADR(targetVariable);
   IF Delay_Start = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Delay_Start = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Delay_Start^; // NULL 체크 없음!
value := Delay_Start.member; // NULL 체크 없음!

✅ 안전: IF Delay_Start <> NULL THEN
value := Delay_Start^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Delay_Start) THEN
value := Delay_Start.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: SEQ_Function_Auto_PID: 1085줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Function_Auto_PID = 1085줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Mode = eAuto_PID_Tune_Zone_1: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_PID_Tune_Zone_1) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_PID_Tune_Zone_1 - 1.0E-6) AND
      Mode <= (eAuto_PID_Tune_Zone_1 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_PID_Tune_Zone_1 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_PID_Tune_Zone_1 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_PID_Tune_Zone_1 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_PID_Tune_Zone_1) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Mode = eAuto_PID_Tune_Zone_2: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_PID_Tune_Zone_2) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_PID_Tune_Zone_2 - 1.0E-6) AND
      Mode <= (eAuto_PID_Tune_Zone_2 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_PID_Tune_Zone_2 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_PID_Tune_Zone_2 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_PID_Tune_Zone_2 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_PID_Tune_Zone_2) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Mode = eAuto_PID_Tune_Zone_3: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_PID_Tune_Zone_3) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_PID_Tune_Zone_3 - 1.0E-6) AND
      Mode <= (eAuto_PID_Tune_Zone_3 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_PID_Tune_Zone_3 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_PID_Tune_Zone_3 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_PID_Tune_Zone_3 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_PID_Tune_Zone_3) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Mode = eAuto_PID_Tune_Zone_4: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_PID_Tune_Zone_4) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_PID_Tune_Zone_4 - 1.0E-6) AND
      Mode <= (eAuto_PID_Tune_Zone_4 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_PID_Tune_Zone_4 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_PID_Tune_Zone_4 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_PID_Tune_Zone_4 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_PID_Tune_Zone_4) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Mode = eAuto_PID_Tune_Zone_5: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_PID_Tune_Zone_5) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_PID_Tune_Zone_5 - 1.0E-6) AND
      Mode <= (eAuto_PID_Tune_Zone_5 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_PID_Tune_Zone_5 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_PID_Tune_Zone_5 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_PID_Tune_Zone_5 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_PID_Tune_Zone_5) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Mode = eAuto_PID_Tune_Zone_6: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_PID_Tune_Zone_6) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_PID_Tune_Zone_6 - 1.0E-6) AND
      Mode <= (eAuto_PID_Tune_Zone_6 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_PID_Tune_Zone_6 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_PID_Tune_Zone_6 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_PID_Tune_Zone_6 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_PID_Tune_Zone_6) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Mode = eAuto_PID_Tune_Zone_7: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_PID_Tune_Zone_7) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_PID_Tune_Zone_7 - 1.0E-6) AND
      Mode <= (eAuto_PID_Tune_Zone_7 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_PID_Tune_Zone_7 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_PID_Tune_Zone_7 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_PID_Tune_Zone_7 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_PID_Tune_Zone_7) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Mode = eAuto_PID_Tune_Zone_8: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_PID_Tune_Zone_8) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_PID_Tune_Zone_8 - 1.0E-6) AND
      Mode <= (eAuto_PID_Tune_Zone_8 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_PID_Tune_Zone_8 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_PID_Tune_Zone_8 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_PID_Tune_Zone_8 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_PID_Tune_Zone_8) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Mode = eAuto_PID_Tune_Zone_9: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_PID_Tune_Zone_9) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_PID_Tune_Zone_9 - 1.0E-6) AND
      Mode <= (eAuto_PID_Tune_Zone_9 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_PID_Tune_Zone_9 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_PID_Tune_Zone_9 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_PID_Tune_Zone_9 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_PID_Tune_Zone_9) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Mode = eAuto_PID_Tune_Zone_10: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_PID_Tune_Zone_10) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_PID_Tune_Zone_10 - 1.0E-6) AND
      Mode <= (eAuto_PID_Tune_Zone_10 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_PID_Tune_Zone_10 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_PID_Tune_Zone_10 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_PID_Tune_Zone_10 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_PID_Tune_Zone_10) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Mode = eAuto_PID_Tune_Zone_11: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_PID_Tune_Zone_11) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_PID_Tune_Zone_11 - 1.0E-6) AND
      Mode <= (eAuto_PID_Tune_Zone_11 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_PID_Tune_Zone_11 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_PID_Tune_Zone_11 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_PID_Tune_Zone_11 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_PID_Tune_Zone_11) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Mode = eAuto_PID_Tune_Zone_12: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_PID_Tune_Zone_12) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_PID_Tune_Zone_12 - 1.0E-6) AND
      Mode <= (eAuto_PID_Tune_Zone_12 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_PID_Tune_Zone_12 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_PID_Tune_Zone_12 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_PID_Tune_Zone_12 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_PID_Tune_Zone_12) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Mode = eAuto_PID_Tune_All_Zone: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_PID_Tune_All_Zone) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_PID_Tune_All_Zone - 1.0E-6) AND
      Mode <= (eAuto_PID_Tune_All_Zone + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_PID_Tune_All_Zone THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_PID_Tune_All_Zone * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_PID_Tune_All_Zone THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_PID_Tune_All_Zone) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Mode = eAuto_PID_Tune_Stop: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_PID_Tune_Stop) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_PID_Tune_Stop - 1.0E-6) AND
      Mode <= (eAuto_PID_Tune_Stop + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_PID_Tune_Stop THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_PID_Tune_Stop * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_PID_Tune_Stop THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_PID_Tune_Stop) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Mode = eAuto_PID_Auto_Start: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_PID_Auto_Start) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_PID_Auto_Start - 1.0E-6) AND
      Mode <= (eAuto_PID_Auto_Start + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_PID_Auto_Start THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_PID_Auto_Start * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_PID_Auto_Start THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_PID_Auto_Start) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Mode = eAuto_PID_Auto_Stop: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_PID_Auto_Stop) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_PID_Auto_Stop - 1.0E-6) AND
      Mode <= (eAuto_PID_Auto_Stop + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_PID_Auto_Stop THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_PID_Auto_Stop * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_PID_Auto_Stop THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_PID_Auto_Stop) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: DO_Heater_Command = eHeaterCommand_Error: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DO_Heater_Command - eHeaterCommand_Error) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DO_Heater_Command >= (eHeaterCommand_Error - 1.0E-6) AND
      DO_Heater_Command <= (eHeaterCommand_Error + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DO_Heater_Command >= eHeaterCommand_Error THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DO_Heater_Command * 10.0);
   intTarget := REAL_TO_DINT(eHeaterCommand_Error * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DO_Heater_Command = eHeaterCommand_Error THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DO_Heater_Command - eHeaterCommand_Error) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: DO_Heater_Command = eHeaterCommand_Idle: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DO_Heater_Command - eHeaterCommand_Idle) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DO_Heater_Command >= (eHeaterCommand_Idle - 1.0E-6) AND
      DO_Heater_Command <= (eHeaterCommand_Idle + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DO_Heater_Command >= eHeaterCommand_Idle THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DO_Heater_Command * 10.0);
   intTarget := REAL_TO_DINT(eHeaterCommand_Idle * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DO_Heater_Command = eHeaterCommand_Idle THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DO_Heater_Command - eHeaterCommand_Idle) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: DO_Heater_Command = eHeaterCommand_Idle: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DO_Heater_Command - eHeaterCommand_Idle) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DO_Heater_Command >= (eHeaterCommand_Idle - 1.0E-6) AND
      DO_Heater_Command <= (eHeaterCommand_Idle + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DO_Heater_Command >= eHeaterCommand_Idle THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DO_Heater_Command * 10.0);
   intTarget := REAL_TO_DINT(eHeaterCommand_Idle * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DO_Heater_Command = eHeaterCommand_Idle THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DO_Heater_Command - eHeaterCommand_Idle) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: DO_Heater_Option_Mode = eHeaterMode_Spike: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DO_Heater_Option_Mode - eHeaterMode_Spike) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DO_Heater_Option_Mode >= (eHeaterMode_Spike - 1.0E-6) AND
      DO_Heater_Option_Mode <= (eHeaterMode_Spike + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DO_Heater_Option_Mode >= eHeaterMode_Spike THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DO_Heater_Option_Mode * 10.0);
   intTarget := REAL_TO_DINT(eHeaterMode_Spike * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DO_Heater_Option_Mode = eHeaterMode_Spike THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DO_Heater_Option_Mode - eHeaterMode_Spike) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: DO_Heater_Option_Mode = eHeaterMode_Profile: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DO_Heater_Option_Mode - eHeaterMode_Profile) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DO_Heater_Option_Mode >= (eHeaterMode_Profile - 1.0E-6) AND
      DO_Heater_Option_Mode <= (eHeaterMode_Profile + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DO_Heater_Option_Mode >= eHeaterMode_Profile THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DO_Heater_Option_Mode * 10.0);
   intTarget := REAL_TO_DINT(eHeaterMode_Profile * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DO_Heater_Option_Mode = eHeaterMode_Profile THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DO_Heater_Option_Mode - eHeaterMode_Profile) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: DO_Heater_Temp_Auto_Tune[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := DO_Heater_Temp_Auto_Tune[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := DO_Heater_Temp_Auto_Tune[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := DO_Heater_Temp_Auto_Tune[Loop];
   END_IF

예시:

❌ 위험: value := DO_Heater_Temp_Auto_Tune[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := DO_Heater_Temp_Auto_Tune[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: DO_Heater_Temp_Auto_Tune[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := DO_Heater_Temp_Auto_Tune[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := DO_Heater_Temp_Auto_Tune[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := DO_Heater_Temp_Auto_Tune[Loop];
   END_IF

예시:

❌ 위험: value := DO_Heater_Temp_Auto_Tune[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := DO_Heater_Temp_Auto_Tune[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: DI_Heater_AT_Spike_Run[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DI_Heater_AT_Spike_Run[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DI_Heater_AT_Spike_Run[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DI_Heater_AT_Spike_Run[i];
   END_IF

예시:

❌ 위험: value := DI_Heater_AT_Spike_Run[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DI_Heater_AT_Spike_Run[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: DI_Heater_AT_Profile_Run[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DI_Heater_AT_Profile_Run[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DI_Heater_AT_Profile_Run[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DI_Heater_AT_Profile_Run[i];
   END_IF

예시:

❌ 위험: value := DI_Heater_AT_Profile_Run[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DI_Heater_AT_Profile_Run[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: eDesc_AutoProfile_Target: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_AutoProfile_Target <> NULL THEN
       value := eDesc_AutoProfile_Target^;
       // 또는 eDesc_AutoProfile_Target.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_AutoProfile_Target');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_AutoProfile_Target) THEN
       value := eDesc_AutoProfile_Target.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_AutoProfile_Target := ADR(targetVariable);
   IF eDesc_AutoProfile_Target = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_AutoProfile_Target = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_AutoProfile_Target^; // NULL 체크 없음!
value := eDesc_AutoProfile_Target.member; // NULL 체크 없음!

✅ 안전: IF eDesc_AutoProfile_Target <> NULL THEN
value := eDesc_AutoProfile_Target^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_AutoProfile_Target) THEN
value := eDesc_AutoProfile_Target.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: eDesc_AutoProfile_Target: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_AutoProfile_Target <> NULL THEN
       value := eDesc_AutoProfile_Target^;
       // 또는 eDesc_AutoProfile_Target.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_AutoProfile_Target');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_AutoProfile_Target) THEN
       value := eDesc_AutoProfile_Target.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_AutoProfile_Target := ADR(targetVariable);
   IF eDesc_AutoProfile_Target = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_AutoProfile_Target = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_AutoProfile_Target^; // NULL 체크 없음!
value := eDesc_AutoProfile_Target.member; // NULL 체크 없음!

✅ 안전: IF eDesc_AutoProfile_Target <> NULL THEN
value := eDesc_AutoProfile_Target^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_AutoProfile_Target) THEN
value := eDesc_AutoProfile_Target.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: pHeater_Profile_Tuned: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pHeater_Profile_Tuned <> NULL THEN
       value := pHeater_Profile_Tuned^;
       // 또는 pHeater_Profile_Tuned.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pHeater_Profile_Tuned');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pHeater_Profile_Tuned) THEN
       value := pHeater_Profile_Tuned.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pHeater_Profile_Tuned := ADR(targetVariable);
   IF pHeater_Profile_Tuned = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pHeater_Profile_Tuned = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pHeater_Profile_Tuned^; // NULL 체크 없음!
value := pHeater_Profile_Tuned.member; // NULL 체크 없음!

✅ 안전: IF pHeater_Profile_Tuned <> NULL THEN
value := pHeater_Profile_Tuned^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pHeater_Profile_Tuned) THEN
value := pHeater_Profile_Tuned.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: eDesc_AutoProfile_Target: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_AutoProfile_Target <> NULL THEN
       value := eDesc_AutoProfile_Target^;
       // 또는 eDesc_AutoProfile_Target.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_AutoProfile_Target');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_AutoProfile_Target) THEN
       value := eDesc_AutoProfile_Target.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_AutoProfile_Target := ADR(targetVariable);
   IF eDesc_AutoProfile_Target = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_AutoProfile_Target = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_AutoProfile_Target^; // NULL 체크 없음!
value := eDesc_AutoProfile_Target.member; // NULL 체크 없음!

✅ 안전: IF eDesc_AutoProfile_Target <> NULL THEN
value := eDesc_AutoProfile_Target^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_AutoProfile_Target) THEN
value := eDesc_AutoProfile_Target.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: pHeater_Profile_Tuned: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pHeater_Profile_Tuned <> NULL THEN
       value := pHeater_Profile_Tuned^;
       // 또는 pHeater_Profile_Tuned.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pHeater_Profile_Tuned');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pHeater_Profile_Tuned) THEN
       value := pHeater_Profile_Tuned.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pHeater_Profile_Tuned := ADR(targetVariable);
   IF pHeater_Profile_Tuned = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pHeater_Profile_Tuned = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pHeater_Profile_Tuned^; // NULL 체크 없음!
value := pHeater_Profile_Tuned.member; // NULL 체크 없음!

✅ 안전: IF pHeater_Profile_Tuned <> NULL THEN
value := pHeater_Profile_Tuned^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pHeater_Profile_Tuned) THEN
value := pHeater_Profile_Tuned.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: eDesc_AutoProfile_Target: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_AutoProfile_Target <> NULL THEN
       value := eDesc_AutoProfile_Target^;
       // 또는 eDesc_AutoProfile_Target.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_AutoProfile_Target');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_AutoProfile_Target) THEN
       value := eDesc_AutoProfile_Target.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_AutoProfile_Target := ADR(targetVariable);
   IF eDesc_AutoProfile_Target = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_AutoProfile_Target = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_AutoProfile_Target^; // NULL 체크 없음!
value := eDesc_AutoProfile_Target.member; // NULL 체크 없음!

✅ 안전: IF eDesc_AutoProfile_Target <> NULL THEN
value := eDesc_AutoProfile_Target^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_AutoProfile_Target) THEN
value := eDesc_AutoProfile_Target.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: pHeater_Profile_Tuned: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pHeater_Profile_Tuned <> NULL THEN
       value := pHeater_Profile_Tuned^;
       // 또는 pHeater_Profile_Tuned.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pHeater_Profile_Tuned');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pHeater_Profile_Tuned) THEN
       value := pHeater_Profile_Tuned.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pHeater_Profile_Tuned := ADR(targetVariable);
   IF pHeater_Profile_Tuned = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pHeater_Profile_Tuned = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pHeater_Profile_Tuned^; // NULL 체크 없음!
value := pHeater_Profile_Tuned.member; // NULL 체크 없음!

✅ 안전: IF pHeater_Profile_Tuned <> NULL THEN
value := pHeater_Profile_Tuned^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pHeater_Profile_Tuned) THEN
value := pHeater_Profile_Tuned.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: eDesc_AutoProfile_Target: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_AutoProfile_Target <> NULL THEN
       value := eDesc_AutoProfile_Target^;
       // 또는 eDesc_AutoProfile_Target.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_AutoProfile_Target');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_AutoProfile_Target) THEN
       value := eDesc_AutoProfile_Target.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_AutoProfile_Target := ADR(targetVariable);
   IF eDesc_AutoProfile_Target = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_AutoProfile_Target = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_AutoProfile_Target^; // NULL 체크 없음!
value := eDesc_AutoProfile_Target.member; // NULL 체크 없음!

✅ 안전: IF eDesc_AutoProfile_Target <> NULL THEN
value := eDesc_AutoProfile_Target^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_AutoProfile_Target) THEN
value := eDesc_AutoProfile_Target.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: pHeater_Profile_Tuned: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pHeater_Profile_Tuned <> NULL THEN
       value := pHeater_Profile_Tuned^;
       // 또는 pHeater_Profile_Tuned.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pHeater_Profile_Tuned');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pHeater_Profile_Tuned) THEN
       value := pHeater_Profile_Tuned.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pHeater_Profile_Tuned := ADR(targetVariable);
   IF pHeater_Profile_Tuned = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pHeater_Profile_Tuned = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pHeater_Profile_Tuned^; // NULL 체크 없음!
value := pHeater_Profile_Tuned.member; // NULL 체크 없음!

✅ 안전: IF pHeater_Profile_Tuned <> NULL THEN
value := pHeater_Profile_Tuned^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pHeater_Profile_Tuned) THEN
value := pHeater_Profile_Tuned.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: eDesc_AutoProfile_Target: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_AutoProfile_Target <> NULL THEN
       value := eDesc_AutoProfile_Target^;
       // 또는 eDesc_AutoProfile_Target.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_AutoProfile_Target');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_AutoProfile_Target) THEN
       value := eDesc_AutoProfile_Target.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_AutoProfile_Target := ADR(targetVariable);
   IF eDesc_AutoProfile_Target = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_AutoProfile_Target = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_AutoProfile_Target^; // NULL 체크 없음!
value := eDesc_AutoProfile_Target.member; // NULL 체크 없음!

✅ 안전: IF eDesc_AutoProfile_Target <> NULL THEN
value := eDesc_AutoProfile_Target^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_AutoProfile_Target) THEN
value := eDesc_AutoProfile_Target.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: pHeater_Profile_Tuned: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pHeater_Profile_Tuned <> NULL THEN
       value := pHeater_Profile_Tuned^;
       // 또는 pHeater_Profile_Tuned.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pHeater_Profile_Tuned');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pHeater_Profile_Tuned) THEN
       value := pHeater_Profile_Tuned.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pHeater_Profile_Tuned := ADR(targetVariable);
   IF pHeater_Profile_Tuned = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pHeater_Profile_Tuned = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pHeater_Profile_Tuned^; // NULL 체크 없음!
value := pHeater_Profile_Tuned.member; // NULL 체크 없음!

✅ 안전: IF pHeater_Profile_Tuned <> NULL THEN
value := pHeater_Profile_Tuned^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pHeater_Profile_Tuned) THEN
value := pHeater_Profile_Tuned.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: eDesc_AutoProfile_Target: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_AutoProfile_Target <> NULL THEN
       value := eDesc_AutoProfile_Target^;
       // 또는 eDesc_AutoProfile_Target.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_AutoProfile_Target');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_AutoProfile_Target) THEN
       value := eDesc_AutoProfile_Target.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_AutoProfile_Target := ADR(targetVariable);
   IF eDesc_AutoProfile_Target = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_AutoProfile_Target = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_AutoProfile_Target^; // NULL 체크 없음!
value := eDesc_AutoProfile_Target.member; // NULL 체크 없음!

✅ 안전: IF eDesc_AutoProfile_Target <> NULL THEN
value := eDesc_AutoProfile_Target^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_AutoProfile_Target) THEN
value := eDesc_AutoProfile_Target.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: pHeater_Profile_Tuned: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pHeater_Profile_Tuned <> NULL THEN
       value := pHeater_Profile_Tuned^;
       // 또는 pHeater_Profile_Tuned.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pHeater_Profile_Tuned');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pHeater_Profile_Tuned) THEN
       value := pHeater_Profile_Tuned.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pHeater_Profile_Tuned := ADR(targetVariable);
   IF pHeater_Profile_Tuned = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pHeater_Profile_Tuned = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pHeater_Profile_Tuned^; // NULL 체크 없음!
value := pHeater_Profile_Tuned.member; // NULL 체크 없음!

✅ 안전: IF pHeater_Profile_Tuned <> NULL THEN
value := pHeater_Profile_Tuned^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pHeater_Profile_Tuned) THEN
value := pHeater_Profile_Tuned.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: eDesc_AutoProfile_Target: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_AutoProfile_Target <> NULL THEN
       value := eDesc_AutoProfile_Target^;
       // 또는 eDesc_AutoProfile_Target.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_AutoProfile_Target');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_AutoProfile_Target) THEN
       value := eDesc_AutoProfile_Target.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_AutoProfile_Target := ADR(targetVariable);
   IF eDesc_AutoProfile_Target = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_AutoProfile_Target = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_AutoProfile_Target^; // NULL 체크 없음!
value := eDesc_AutoProfile_Target.member; // NULL 체크 없음!

✅ 안전: IF eDesc_AutoProfile_Target <> NULL THEN
value := eDesc_AutoProfile_Target^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_AutoProfile_Target) THEN
value := eDesc_AutoProfile_Target.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: pHeater_Profile_Tuned: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pHeater_Profile_Tuned <> NULL THEN
       value := pHeater_Profile_Tuned^;
       // 또는 pHeater_Profile_Tuned.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pHeater_Profile_Tuned');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pHeater_Profile_Tuned) THEN
       value := pHeater_Profile_Tuned.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pHeater_Profile_Tuned := ADR(targetVariable);
   IF pHeater_Profile_Tuned = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pHeater_Profile_Tuned = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pHeater_Profile_Tuned^; // NULL 체크 없음!
value := pHeater_Profile_Tuned.member; // NULL 체크 없음!

✅ 안전: IF pHeater_Profile_Tuned <> NULL THEN
value := pHeater_Profile_Tuned^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pHeater_Profile_Tuned) THEN
value := pHeater_Profile_Tuned.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: pProfile_Tune: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pProfile_Tune <> NULL THEN
       value := pProfile_Tune^;
       // 또는 pProfile_Tune.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pProfile_Tune');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pProfile_Tune) THEN
       value := pProfile_Tune.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pProfile_Tune := ADR(targetVariable);
   IF pProfile_Tune = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pProfile_Tune = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pProfile_Tune^; // NULL 체크 없음!
value := pProfile_Tune.member; // NULL 체크 없음!

✅ 안전: IF pProfile_Tune <> NULL THEN
value := pProfile_Tune^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pProfile_Tune) THEN
value := pProfile_Tune.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: pProfile_Tune: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pProfile_Tune <> NULL THEN
       value := pProfile_Tune^;
       // 또는 pProfile_Tune.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pProfile_Tune');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pProfile_Tune) THEN
       value := pProfile_Tune.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pProfile_Tune := ADR(targetVariable);
   IF pProfile_Tune = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pProfile_Tune = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pProfile_Tune^; // NULL 체크 없음!
value := pProfile_Tune.member; // NULL 체크 없음!

✅ 안전: IF pProfile_Tune <> NULL THEN
value := pProfile_Tune^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pProfile_Tune) THEN
value := pProfile_Tune.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: pProfile_Tune: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pProfile_Tune <> NULL THEN
       value := pProfile_Tune^;
       // 또는 pProfile_Tune.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pProfile_Tune');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pProfile_Tune) THEN
       value := pProfile_Tune.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pProfile_Tune := ADR(targetVariable);
   IF pProfile_Tune = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pProfile_Tune = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pProfile_Tune^; // NULL 체크 없음!
value := pProfile_Tune.member; // NULL 체크 없음!

✅ 안전: IF pProfile_Tune <> NULL THEN
value := pProfile_Tune^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pProfile_Tune) THEN
value := pProfile_Tune.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: SEQ_Function_Auto_Profile: 338줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Function_Auto_Profile = 338줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: Mode = eAuto_Tune_Run: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_Tune_Run) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_Tune_Run - 1.0E-6) AND
      Mode <= (eAuto_Tune_Run + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_Tune_Run THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_Tune_Run * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_Tune_Run THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_Tune_Run) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: Mode = eAuto_Tune_Auto_Run: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_Tune_Auto_Run) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_Tune_Auto_Run - 1.0E-6) AND
      Mode <= (eAuto_Tune_Auto_Run + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_Tune_Auto_Run THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_Tune_Auto_Run * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_Tune_Auto_Run THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_Tune_Auto_Run) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: Mode = eAuto_Tune_Stop: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_Tune_Stop) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_Tune_Stop - 1.0E-6) AND
      Mode <= (eAuto_Tune_Stop + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_Tune_Stop THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_Tune_Stop * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_Tune_Stop THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_Tune_Stop) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: Ctrl = eStop: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eStop) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eStop - 1.0E-6) AND
      Ctrl <= (eStop + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eStop THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eStop * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eStop THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eStop) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: Range[Profile_TC_Save_Target]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Profile_TC_Save_Target >= 1 AND
      Profile_TC_Save_Target <= 10 THEN
       value := Range[Profile_TC_Save_Target];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Profile_TC_Save_Target, 10);
   value := Range[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Profile_TC_Save_Target >= ARRAY_MIN AND Profile_TC_Save_Target <= ARRAY_MAX THEN
       value := Range[Profile_TC_Save_Target];
   END_IF

예시:

❌ 위험: value := Range[Profile_TC_Save_Target]; // 범위 검사 없음!

✅ 안전: IF Profile_TC_Save_Target >= 1 AND Profile_TC_Save_Target <= 10 THEN
value := Range[Profile_TC_Save_Target];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: Time_Sleep: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Time_Sleep <> NULL THEN
       value := Time_Sleep^;
       // 또는 Time_Sleep.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Time_Sleep');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Time_Sleep) THEN
       value := Time_Sleep.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Time_Sleep := ADR(targetVariable);
   IF Time_Sleep = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Time_Sleep = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Time_Sleep^; // NULL 체크 없음!
value := Time_Sleep.member; // NULL 체크 없음!

✅ 안전: IF Time_Sleep <> NULL THEN
value := Time_Sleep^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Time_Sleep) THEN
value := Time_Sleep.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: SEQ_Function_Auto_RDNP: 340줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Function_Auto_RDNP = 340줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: Mode = eAuto_Tune_Run: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_Tune_Run) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_Tune_Run - 1.0E-6) AND
      Mode <= (eAuto_Tune_Run + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_Tune_Run THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_Tune_Run * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_Tune_Run THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_Tune_Run) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: Mode = eAuto_Tune_Stop: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_Tune_Stop) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_Tune_Stop - 1.0E-6) AND
      Mode <= (eAuto_Tune_Stop + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_Tune_Stop THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_Tune_Stop * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_Tune_Stop THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_Tune_Stop) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: Mode = eAuto_Tune_Auto_Stop: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_Tune_Auto_Stop) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_Tune_Auto_Stop - 1.0E-6) AND
      Mode <= (eAuto_Tune_Auto_Stop + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_Tune_Auto_Stop THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_Tune_Auto_Stop * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_Tune_Auto_Stop THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_Tune_Auto_Stop) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: Mode = eAuto_Tune_Auto_Run: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAuto_Tune_Auto_Run) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAuto_Tune_Auto_Run - 1.0E-6) AND
      Mode <= (eAuto_Tune_Auto_Run + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAuto_Tune_Auto_Run THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAuto_Tune_Auto_Run * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAuto_Tune_Auto_Run THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAuto_Tune_Auto_Run) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: DO_Heater_Command = eHeaterCommand_Idle: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DO_Heater_Command - eHeaterCommand_Idle) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DO_Heater_Command >= (eHeaterCommand_Idle - 1.0E-6) AND
      DO_Heater_Command <= (eHeaterCommand_Idle + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DO_Heater_Command >= eHeaterCommand_Idle THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DO_Heater_Command * 10.0);
   intTarget := REAL_TO_DINT(eHeaterCommand_Idle * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DO_Heater_Command = eHeaterCommand_Idle THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DO_Heater_Command - eHeaterCommand_Idle) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: DO_Heater_Command = eHeaterCommand_Idle: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DO_Heater_Command - eHeaterCommand_Idle) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DO_Heater_Command >= (eHeaterCommand_Idle - 1.0E-6) AND
      DO_Heater_Command <= (eHeaterCommand_Idle + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DO_Heater_Command >= eHeaterCommand_Idle THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DO_Heater_Command * 10.0);
   intTarget := REAL_TO_DINT(eHeaterCommand_Idle * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DO_Heater_Command = eHeaterCommand_Idle THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DO_Heater_Command - eHeaterCommand_Idle) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: DO_Heater_Option_Mode = eHeaterMode_Spike: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DO_Heater_Option_Mode - eHeaterMode_Spike) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DO_Heater_Option_Mode >= (eHeaterMode_Spike - 1.0E-6) AND
      DO_Heater_Option_Mode <= (eHeaterMode_Spike + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DO_Heater_Option_Mode >= eHeaterMode_Spike THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DO_Heater_Option_Mode * 10.0);
   intTarget := REAL_TO_DINT(eHeaterMode_Spike * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DO_Heater_Option_Mode = eHeaterMode_Spike THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DO_Heater_Option_Mode - eHeaterMode_Spike) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: DI_Heater_Temp_Auto_Over_Result[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := DI_Heater_Temp_Auto_Over_Result[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := DI_Heater_Temp_Auto_Over_Result[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := DI_Heater_Temp_Auto_Over_Result[Loop];
   END_IF

예시:

❌ 위험: value := DI_Heater_Temp_Auto_Over_Result[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := DI_Heater_Temp_Auto_Over_Result[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: DI_Heater_Temp_Auto_Under_Result[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := DI_Heater_Temp_Auto_Under_Result[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := DI_Heater_Temp_Auto_Under_Result[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := DI_Heater_Temp_Auto_Under_Result[Loop];
   END_IF

예시:

❌ 위험: value := DI_Heater_Temp_Auto_Under_Result[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := DI_Heater_Temp_Auto_Under_Result[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: AI_Heater_WS[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := AI_Heater_WS[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := AI_Heater_WS[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := AI_Heater_WS[Loop];
   END_IF

예시:

❌ 위험: value := AI_Heater_WS[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := AI_Heater_WS[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: AI_Heater_SV[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := AI_Heater_SV[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := AI_Heater_SV[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := AI_Heater_SV[Loop];
   END_IF

예시:

❌ 위험: value := AI_Heater_SV[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := AI_Heater_SV[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: AI_Heater_PV_Spike[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := AI_Heater_PV_Spike[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := AI_Heater_PV_Spike[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := AI_Heater_PV_Spike[Loop];
   END_IF

예시:

❌ 위험: value := AI_Heater_PV_Spike[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := AI_Heater_PV_Spike[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: pHeater_Temp_Auto_Tune_OverShoot[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := pHeater_Temp_Auto_Tune_OverShoot[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := pHeater_Temp_Auto_Tune_OverShoot[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := pHeater_Temp_Auto_Tune_OverShoot[Loop];
   END_IF

예시:

❌ 위험: value := pHeater_Temp_Auto_Tune_OverShoot[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := pHeater_Temp_Auto_Tune_OverShoot[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: DI_Heater_Temp_Auto_Over_Result[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := DI_Heater_Temp_Auto_Over_Result[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := DI_Heater_Temp_Auto_Over_Result[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := DI_Heater_Temp_Auto_Over_Result[Loop];
   END_IF

예시:

❌ 위험: value := DI_Heater_Temp_Auto_Over_Result[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := DI_Heater_Temp_Auto_Over_Result[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: AI_Heater_PV_Spike[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := AI_Heater_PV_Spike[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := AI_Heater_PV_Spike[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := AI_Heater_PV_Spike[Loop];
   END_IF

예시:

❌ 위험: value := AI_Heater_PV_Spike[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := AI_Heater_PV_Spike[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: pHeater_Temp_Auto_Tune_UnderShoot[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := pHeater_Temp_Auto_Tune_UnderShoot[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := pHeater_Temp_Auto_Tune_UnderShoot[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := pHeater_Temp_Auto_Tune_UnderShoot[Loop];
   END_IF

예시:

❌ 위험: value := pHeater_Temp_Auto_Tune_UnderShoot[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := pHeater_Temp_Auto_Tune_UnderShoot[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: DI_Heater_Temp_Auto_Under_Result[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := DI_Heater_Temp_Auto_Under_Result[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := DI_Heater_Temp_Auto_Under_Result[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := DI_Heater_Temp_Auto_Under_Result[Loop];
   END_IF

예시:

❌ 위험: value := DI_Heater_Temp_Auto_Under_Result[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := DI_Heater_Temp_Auto_Under_Result[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: DI_Heater_Temp_Auto_Over_Result[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := DI_Heater_Temp_Auto_Over_Result[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := DI_Heater_Temp_Auto_Over_Result[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := DI_Heater_Temp_Auto_Over_Result[Loop];
   END_IF

예시:

❌ 위험: value := DI_Heater_Temp_Auto_Over_Result[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := DI_Heater_Temp_Auto_Over_Result[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: DI_Heater_Temp_Auto_Under_Result[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := DI_Heater_Temp_Auto_Under_Result[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := DI_Heater_Temp_Auto_Under_Result[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := DI_Heater_Temp_Auto_Under_Result[Loop];
   END_IF

예시:

❌ 위험: value := DI_Heater_Temp_Auto_Under_Result[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := DI_Heater_Temp_Auto_Under_Result[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: AI_Heater_PV_Profile[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := AI_Heater_PV_Profile[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := AI_Heater_PV_Profile[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := AI_Heater_PV_Profile[Loop];
   END_IF

예시:

❌ 위험: value := AI_Heater_PV_Profile[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := AI_Heater_PV_Profile[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: pHeater_Temp_Auto_Tune_OverShoot[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := pHeater_Temp_Auto_Tune_OverShoot[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := pHeater_Temp_Auto_Tune_OverShoot[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := pHeater_Temp_Auto_Tune_OverShoot[Loop];
   END_IF

예시:

❌ 위험: value := pHeater_Temp_Auto_Tune_OverShoot[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := pHeater_Temp_Auto_Tune_OverShoot[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: DI_Heater_Temp_Auto_Over_Result[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := DI_Heater_Temp_Auto_Over_Result[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := DI_Heater_Temp_Auto_Over_Result[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := DI_Heater_Temp_Auto_Over_Result[Loop];
   END_IF

예시:

❌ 위험: value := DI_Heater_Temp_Auto_Over_Result[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := DI_Heater_Temp_Auto_Over_Result[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: AI_Heater_PV_Profile[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := AI_Heater_PV_Profile[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := AI_Heater_PV_Profile[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := AI_Heater_PV_Profile[Loop];
   END_IF

예시:

❌ 위험: value := AI_Heater_PV_Profile[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := AI_Heater_PV_Profile[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: pHeater_Temp_Auto_Tune_UnderShoot[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := pHeater_Temp_Auto_Tune_UnderShoot[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := pHeater_Temp_Auto_Tune_UnderShoot[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := pHeater_Temp_Auto_Tune_UnderShoot[Loop];
   END_IF

예시:

❌ 위험: value := pHeater_Temp_Auto_Tune_UnderShoot[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := pHeater_Temp_Auto_Tune_UnderShoot[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: DI_Heater_Temp_Auto_Under_Result[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := DI_Heater_Temp_Auto_Under_Result[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := DI_Heater_Temp_Auto_Under_Result[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := DI_Heater_Temp_Auto_Under_Result[Loop];
   END_IF

예시:

❌ 위험: value := DI_Heater_Temp_Auto_Under_Result[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := DI_Heater_Temp_Auto_Under_Result[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: DI_Heater_Temp_Auto_Over_Result[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := DI_Heater_Temp_Auto_Over_Result[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := DI_Heater_Temp_Auto_Over_Result[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := DI_Heater_Temp_Auto_Over_Result[Loop];
   END_IF

예시:

❌ 위험: value := DI_Heater_Temp_Auto_Over_Result[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := DI_Heater_Temp_Auto_Over_Result[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: DI_Heater_Temp_Auto_Under_Result[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := DI_Heater_Temp_Auto_Under_Result[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := DI_Heater_Temp_Auto_Under_Result[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := DI_Heater_Temp_Auto_Under_Result[Loop];
   END_IF

예시:

❌ 위험: value := DI_Heater_Temp_Auto_Under_Result[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := DI_Heater_Temp_Auto_Under_Result[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: DI_Heater_Temp_Auto_Over_Result[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := DI_Heater_Temp_Auto_Over_Result[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := DI_Heater_Temp_Auto_Over_Result[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := DI_Heater_Temp_Auto_Over_Result[Loop];
   END_IF

예시:

❌ 위험: value := DI_Heater_Temp_Auto_Over_Result[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := DI_Heater_Temp_Auto_Over_Result[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: DI_Heater_Temp_Auto_Under_Result[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := DI_Heater_Temp_Auto_Under_Result[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := DI_Heater_Temp_Auto_Under_Result[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := DI_Heater_Temp_Auto_Under_Result[Loop];
   END_IF

예시:

❌ 위험: value := DI_Heater_Temp_Auto_Under_Result[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := DI_Heater_Temp_Auto_Under_Result[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: 1: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 1 <> NULL THEN
       value := 1^;
       // 또는 1.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 1');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(1) THEN
       value := 1.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   1 := ADR(targetVariable);
   IF 1 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 1 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 1^; // NULL 체크 없음!
value := 1.member; // NULL 체크 없음!

✅ 안전: IF 1 <> NULL THEN
value := 1^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(1) THEN
value := 1.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: 2: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 2 <> NULL THEN
       value := 2^;
       // 또는 2.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 2');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(2) THEN
       value := 2.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   2 := ADR(targetVariable);
   IF 2 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 2 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 2^; // NULL 체크 없음!
value := 2.member; // NULL 체크 없음!

✅ 안전: IF 2 <> NULL THEN
value := 2^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(2) THEN
value := 2.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: 3: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 3 <> NULL THEN
       value := 3^;
       // 또는 3.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 3');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(3) THEN
       value := 3.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   3 := ADR(targetVariable);
   IF 3 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 3 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 3^; // NULL 체크 없음!
value := 3.member; // NULL 체크 없음!

✅ 안전: IF 3 <> NULL THEN
value := 3^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(3) THEN
value := 3.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: 1: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 1 <> NULL THEN
       value := 1^;
       // 또는 1.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 1');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(1) THEN
       value := 1.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   1 := ADR(targetVariable);
   IF 1 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 1 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 1^; // NULL 체크 없음!
value := 1.member; // NULL 체크 없음!

✅ 안전: IF 1 <> NULL THEN
value := 1^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(1) THEN
value := 1.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: eIndex_MFC: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eIndex_MFC <> NULL THEN
       value := eIndex_MFC^;
       // 또는 eIndex_MFC.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eIndex_MFC');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eIndex_MFC) THEN
       value := eIndex_MFC.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eIndex_MFC := ADR(targetVariable);
   IF eIndex_MFC = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eIndex_MFC = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eIndex_MFC^; // NULL 체크 없음!
value := eIndex_MFC.member; // NULL 체크 없음!

✅ 안전: IF eIndex_MFC <> NULL THEN
value := eIndex_MFC^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eIndex_MFC) THEN
value := eIndex_MFC.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: eIndex_MFC: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eIndex_MFC <> NULL THEN
       value := eIndex_MFC^;
       // 또는 eIndex_MFC.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eIndex_MFC');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eIndex_MFC) THEN
       value := eIndex_MFC.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eIndex_MFC := ADR(targetVariable);
   IF eIndex_MFC = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eIndex_MFC = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eIndex_MFC^; // NULL 체크 없음!
value := eIndex_MFC.member; // NULL 체크 없음!

✅ 안전: IF eIndex_MFC <> NULL THEN
value := eIndex_MFC^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eIndex_MFC) THEN
value := eIndex_MFC.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: 3: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 3 <> NULL THEN
       value := 3^;
       // 또는 3.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 3');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(3) THEN
       value := 3.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   3 := ADR(targetVariable);
   IF 3 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 3 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 3^; // NULL 체크 없음!
value := 3.member; // NULL 체크 없음!

✅ 안전: IF 3 <> NULL THEN
value := 3^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(3) THEN
value := 3.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: tWait: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF tWait <> NULL THEN
       value := tWait^;
       // 또는 tWait.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: tWait');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(tWait) THEN
       value := tWait.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   tWait := ADR(targetVariable);
   IF tWait = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF tWait = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := tWait^; // NULL 체크 없음!
value := tWait.member; // NULL 체크 없음!

✅ 안전: IF tWait <> NULL THEN
value := tWait^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(tWait) THEN
value := tWait.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: eIndex_MFC: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eIndex_MFC <> NULL THEN
       value := eIndex_MFC^;
       // 또는 eIndex_MFC.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eIndex_MFC');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eIndex_MFC) THEN
       value := eIndex_MFC.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eIndex_MFC := ADR(targetVariable);
   IF eIndex_MFC = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eIndex_MFC = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eIndex_MFC^; // NULL 체크 없음!
value := eIndex_MFC.member; // NULL 체크 없음!

✅ 안전: IF eIndex_MFC <> NULL THEN
value := eIndex_MFC^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eIndex_MFC) THEN
value := eIndex_MFC.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: 1: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 1 <> NULL THEN
       value := 1^;
       // 또는 1.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 1');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(1) THEN
       value := 1.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   1 := ADR(targetVariable);
   IF 1 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 1 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 1^; // NULL 체크 없음!
value := 1.member; // NULL 체크 없음!

✅ 안전: IF 1 <> NULL THEN
value := 1^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(1) THEN
value := 1.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: SEQ_Function_PartsPara: 244줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Function_PartsPara = 244줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: DX_CFG_PartsPara_Log_Use = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_CFG_PartsPara_Log_Use - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_CFG_PartsPara_Log_Use >= (FALSE - 1.0E-6) AND
      DX_CFG_PartsPara_Log_Use <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_CFG_PartsPara_Log_Use >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_CFG_PartsPara_Log_Use * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_CFG_PartsPara_Log_Use = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_CFG_PartsPara_Log_Use - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: DX_CFG_MFC_PartsPara_Log_Use = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_CFG_MFC_PartsPara_Log_Use - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_CFG_MFC_PartsPara_Log_Use >= (FALSE - 1.0E-6) AND
      DX_CFG_MFC_PartsPara_Log_Use <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_CFG_MFC_PartsPara_Log_Use >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_CFG_MFC_PartsPara_Log_Use * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_CFG_MFC_PartsPara_Log_Use = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_CFG_MFC_PartsPara_Log_Use - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: pPartsPara_Trig = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(pPartsPara_Trig - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF pPartsPara_Trig >= (FALSE - 1.0E-6) AND
      pPartsPara_Trig <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF pPartsPara_Trig >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(pPartsPara_Trig * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF pPartsPara_Trig = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(pPartsPara_Trig - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: LogEvent = 1: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(LogEvent - 1) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF LogEvent >= (1 - 1.0E-6) AND
      LogEvent <= (1 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF LogEvent >= 1 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(LogEvent * 10.0);
   intTarget := REAL_TO_DINT(1 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF LogEvent = 1 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(LogEvent - 1) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: LogEvent = 2: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(LogEvent - 2) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF LogEvent >= (2 - 1.0E-6) AND
      LogEvent <= (2 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF LogEvent >= 2 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(LogEvent * 10.0);
   intTarget := REAL_TO_DINT(2 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF LogEvent = 2 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(LogEvent - 2) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: bInformation = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(bInformation - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF bInformation >= (TRUE - 1.0E-6) AND
      bInformation <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF bInformation >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(bInformation * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF bInformation = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(bInformation - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Ctrl[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Ctrl[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Ctrl[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Ctrl[i];
   END_IF

예시:

❌ 위험: value := Ctrl[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Ctrl[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Timeout[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Timeout[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Timeout[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Timeout[i];
   END_IF

예시:

❌ 위험: value := Timeout[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Timeout[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: gOldMfcNotOPState[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := gOldMfcNotOPState[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := gOldMfcNotOPState[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := gOldMfcNotOPState[i];
   END_IF

예시:

❌ 위험: value := gOldMfcNotOPState[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := gOldMfcNotOPState[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Ctrl[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Ctrl[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Ctrl[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Ctrl[i];
   END_IF

예시:

❌ 위험: value := Ctrl[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Ctrl[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Timeout[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Timeout[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Timeout[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Timeout[i];
   END_IF

예시:

❌ 위험: value := Timeout[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Timeout[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: gOldMfcNotOPState[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := gOldMfcNotOPState[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := gOldMfcNotOPState[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := gOldMfcNotOPState[i];
   END_IF

예시:

❌ 위험: value := gOldMfcNotOPState[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := gOldMfcNotOPState[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Ctrl[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Ctrl[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Ctrl[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Ctrl[i];
   END_IF

예시:

❌ 위험: value := Ctrl[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Ctrl[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Timeout[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Timeout[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Timeout[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Timeout[i];
   END_IF

예시:

❌ 위험: value := Timeout[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Timeout[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Mode[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Mode[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Mode[i];
   END_IF

예시:

❌ 위험: value := Mode[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Mode[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Mode[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Mode[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Mode[i];
   END_IF

예시:

❌ 위험: value := Mode[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Mode[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Timeout[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Timeout[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Timeout[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Timeout[i];
   END_IF

예시:

❌ 위험: value := Timeout[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Timeout[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Step[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Step[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Step[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Step[i];
   END_IF

예시:

❌ 위험: value := Step[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Step[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: pPartsPara[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := pPartsPara[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := pPartsPara[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := pPartsPara[i];
   END_IF

예시:

❌ 위험: value := pPartsPara[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := pPartsPara[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: pPartsPara[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := pPartsPara[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := pPartsPara[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := pPartsPara[i];
   END_IF

예시:

❌ 위험: value := pPartsPara[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := pPartsPara[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Ctrl[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Ctrl[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Ctrl[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Ctrl[i];
   END_IF

예시:

❌ 위험: value := Ctrl[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Ctrl[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: gOldMfcNotOPState[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := gOldMfcNotOPState[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := gOldMfcNotOPState[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := gOldMfcNotOPState[i];
   END_IF

예시:

❌ 위험: value := gOldMfcNotOPState[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := gOldMfcNotOPState[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Ctrl[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Ctrl[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Ctrl[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Ctrl[i];
   END_IF

예시:

❌ 위험: value := Ctrl[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Ctrl[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: pPartsPara[Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Item >= 1 AND
      Item <= 10 THEN
       value := pPartsPara[Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Item, 10);
   value := pPartsPara[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Item >= ARRAY_MIN AND Item <= ARRAY_MAX THEN
       value := pPartsPara[Item];
   END_IF

예시:

❌ 위험: value := pPartsPara[Item]; // 범위 검사 없음!

✅ 안전: IF Item >= 1 AND Item <= 10 THEN
value := pPartsPara[Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Item[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Item[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Item[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Item[i];
   END_IF

예시:

❌ 위험: value := Item[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Item[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: pPartsPara[Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Item >= 1 AND
      Item <= 10 THEN
       value := pPartsPara[Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Item, 10);
   value := pPartsPara[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Item >= ARRAY_MIN AND Item <= ARRAY_MAX THEN
       value := pPartsPara[Item];
   END_IF

예시:

❌ 위험: value := pPartsPara[Item]; // 범위 검사 없음!

✅ 안전: IF Item >= 1 AND Item <= 10 THEN
value := pPartsPara[Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Item[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Item[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Item[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Item[i];
   END_IF

예시:

❌ 위험: value := Item[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Item[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: pPartsPara[Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Item >= 1 AND
      Item <= 10 THEN
       value := pPartsPara[Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Item, 10);
   value := pPartsPara[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Item >= ARRAY_MIN AND Item <= ARRAY_MAX THEN
       value := pPartsPara[Item];
   END_IF

예시:

❌ 위험: value := pPartsPara[Item]; // 범위 검사 없음!

✅ 안전: IF Item >= 1 AND Item <= 10 THEN
value := pPartsPara[Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Item[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Item[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Item[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Item[i];
   END_IF

예시:

❌ 위험: value := Item[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Item[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: pPartsPara[Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Item >= 1 AND
      Item <= 10 THEN
       value := pPartsPara[Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Item, 10);
   value := pPartsPara[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Item >= ARRAY_MIN AND Item <= ARRAY_MAX THEN
       value := pPartsPara[Item];
   END_IF

예시:

❌ 위험: value := pPartsPara[Item]; // 범위 검사 없음!

✅ 안전: IF Item >= 1 AND Item <= 10 THEN
value := pPartsPara[Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Item[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Item[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Item[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Item[i];
   END_IF

예시:

❌ 위험: value := Item[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Item[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: pPartsPara[Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Item >= 1 AND
      Item <= 10 THEN
       value := pPartsPara[Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Item, 10);
   value := pPartsPara[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Item >= ARRAY_MIN AND Item <= ARRAY_MAX THEN
       value := pPartsPara[Item];
   END_IF

예시:

❌ 위험: value := pPartsPara[Item]; // 범위 검사 없음!

✅ 안전: IF Item >= 1 AND Item <= 10 THEN
value := pPartsPara[Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Item[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Item[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Item[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Item[i];
   END_IF

예시:

❌ 위험: value := Item[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Item[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: pPartsPara[Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Item >= 1 AND
      Item <= 10 THEN
       value := pPartsPara[Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Item, 10);
   value := pPartsPara[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Item >= ARRAY_MIN AND Item <= ARRAY_MAX THEN
       value := pPartsPara[Item];
   END_IF

예시:

❌ 위험: value := pPartsPara[Item]; // 범위 검사 없음!

✅ 안전: IF Item >= 1 AND Item <= 10 THEN
value := pPartsPara[Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Item[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Item[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Item[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Item[i];
   END_IF

예시:

❌ 위험: value := Item[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Item[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: pPartsPara[Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Item >= 1 AND
      Item <= 10 THEN
       value := pPartsPara[Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Item, 10);
   value := pPartsPara[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Item >= ARRAY_MIN AND Item <= ARRAY_MAX THEN
       value := pPartsPara[Item];
   END_IF

예시:

❌ 위험: value := pPartsPara[Item]; // 범위 검사 없음!

✅ 안전: IF Item >= 1 AND Item <= 10 THEN
value := pPartsPara[Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: Item[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Item[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Item[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Item[i];
   END_IF

예시:

❌ 위험: value := Item[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Item[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:1

설명: SEQ_Function_Process: 9171줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Function_Process = 9171줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:1

설명: ARRAY[1..cMAX_SubRecipe]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_SubRecipe >= 1 AND
      1..cMAX_SubRecipe <= 10 THEN
       value := ARRAY[1..cMAX_SubRecipe];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_SubRecipe, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_SubRecipe >= ARRAY_MIN AND 1..cMAX_SubRecipe <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_SubRecipe];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_SubRecipe]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_SubRecipe >= 1 AND 1..cMAX_SubRecipe <= 10 THEN
value := ARRAY[1..cMAX_SubRecipe];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:1

설명: ARRAY[1..cMAX_Recipe_Step]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Recipe_Step >= 1 AND
      1..cMAX_Recipe_Step <= 10 THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Recipe_Step, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Recipe_Step >= ARRAY_MIN AND 1..cMAX_Recipe_Step <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Recipe_Step];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Recipe_Step]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Recipe_Step >= 1 AND 1..cMAX_Recipe_Step <= 10 THEN
value := ARRAY[1..cMAX_Recipe_Step];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: TransferCheck: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF TransferCheck <> NULL THEN
       value := TransferCheck^;
       // 또는 TransferCheck.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: TransferCheck');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(TransferCheck) THEN
       value := TransferCheck.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   TransferCheck := ADR(targetVariable);
   IF TransferCheck = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF TransferCheck = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := TransferCheck^; // NULL 체크 없음!
value := TransferCheck.member; // NULL 체크 없음!

✅ 안전: IF TransferCheck <> NULL THEN
value := TransferCheck^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(TransferCheck) THEN
value := TransferCheck.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: TransferCheck: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF TransferCheck <> NULL THEN
       value := TransferCheck^;
       // 또는 TransferCheck.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: TransferCheck');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(TransferCheck) THEN
       value := TransferCheck.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   TransferCheck := ADR(targetVariable);
   IF TransferCheck = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF TransferCheck = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := TransferCheck^; // NULL 체크 없음!
value := TransferCheck.member; // NULL 체크 없음!

✅ 안전: IF TransferCheck <> NULL THEN
value := TransferCheck^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(TransferCheck) THEN
value := TransferCheck.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Sleep: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Sleep <> NULL THEN
       value := Sleep^;
       // 또는 Sleep.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Sleep');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Sleep) THEN
       value := Sleep.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Sleep := ADR(targetVariable);
   IF Sleep = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Sleep = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Sleep^; // NULL 체크 없음!
value := Sleep.member; // NULL 체크 없음!

✅ 안전: IF Sleep <> NULL THEN
value := Sleep^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Sleep) THEN
value := Sleep.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: SEQ_Interface: 1323줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Interface = 1323줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Mode = eAUTO_INIT: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAUTO_INIT) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAUTO_INIT - 1.0E-6) AND
      Mode <= (eAUTO_INIT + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAUTO_INIT THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAUTO_INIT * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAUTO_INIT THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAUTO_INIT) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Mode = eSYSTEM_INIT: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eSYSTEM_INIT) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eSYSTEM_INIT - 1.0E-6) AND
      Mode <= (eSYSTEM_INIT + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eSYSTEM_INIT THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eSYSTEM_INIT * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eSYSTEM_INIT THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eSYSTEM_INIT) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Mode = eSYSTEM_MAINT: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eSYSTEM_MAINT) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eSYSTEM_MAINT - 1.0E-6) AND
      Mode <= (eSYSTEM_MAINT + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eSYSTEM_MAINT THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eSYSTEM_MAINT * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eSYSTEM_MAINT THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eSYSTEM_MAINT) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Mode = eSYSTEM_DOWN: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eSYSTEM_DOWN) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eSYSTEM_DOWN - 1.0E-6) AND
      Mode <= (eSYSTEM_DOWN + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eSYSTEM_DOWN THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eSYSTEM_DOWN * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eSYSTEM_DOWN THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eSYSTEM_DOWN) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Mode = ePICK_READY: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - ePICK_READY) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (ePICK_READY - 1.0E-6) AND
      Mode <= (ePICK_READY + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= ePICK_READY THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(ePICK_READY * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = ePICK_READY THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - ePICK_READY) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Mode = ePICK_X_READY: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - ePICK_X_READY) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (ePICK_X_READY - 1.0E-6) AND
      Mode <= (ePICK_X_READY + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= ePICK_X_READY THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(ePICK_X_READY * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = ePICK_X_READY THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - ePICK_X_READY) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Mode = ePICK_COMPLETE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - ePICK_COMPLETE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (ePICK_COMPLETE - 1.0E-6) AND
      Mode <= (ePICK_COMPLETE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= ePICK_COMPLETE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(ePICK_COMPLETE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = ePICK_COMPLETE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - ePICK_COMPLETE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Mode = ePICK_X_COMPLETE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - ePICK_X_COMPLETE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (ePICK_X_COMPLETE - 1.0E-6) AND
      Mode <= (ePICK_X_COMPLETE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= ePICK_X_COMPLETE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(ePICK_X_COMPLETE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = ePICK_X_COMPLETE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - ePICK_X_COMPLETE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Mode = ePLACE_READY: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - ePLACE_READY) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (ePLACE_READY - 1.0E-6) AND
      Mode <= (ePLACE_READY + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= ePLACE_READY THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(ePLACE_READY * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = ePLACE_READY THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - ePLACE_READY) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Mode = ePLACE_X_READY: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - ePLACE_X_READY) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (ePLACE_X_READY - 1.0E-6) AND
      Mode <= (ePLACE_X_READY + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= ePLACE_X_READY THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(ePLACE_X_READY * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = ePLACE_X_READY THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - ePLACE_X_READY) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Mode = ePLACE_COMPLETE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - ePLACE_COMPLETE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (ePLACE_COMPLETE - 1.0E-6) AND
      Mode <= (ePLACE_COMPLETE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= ePLACE_COMPLETE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(ePLACE_COMPLETE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = ePLACE_COMPLETE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - ePLACE_COMPLETE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Mode = ePLACE_X_COMPLETE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - ePLACE_X_COMPLETE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (ePLACE_X_COMPLETE - 1.0E-6) AND
      Mode <= (ePLACE_X_COMPLETE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= ePLACE_X_COMPLETE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(ePLACE_X_COMPLETE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = ePLACE_X_COMPLETE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - ePLACE_X_COMPLETE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Mode = ePRO_READY: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - ePRO_READY) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (ePRO_READY - 1.0E-6) AND
      Mode <= (ePRO_READY + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= ePRO_READY THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(ePRO_READY * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = ePRO_READY THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - ePRO_READY) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Mode = ePRO_START: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - ePRO_START) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (ePRO_START - 1.0E-6) AND
      Mode <= (ePRO_START + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= ePRO_START THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(ePRO_START * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = ePRO_START THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - ePRO_START) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Mode = eMNT_READY: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMNT_READY) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMNT_READY - 1.0E-6) AND
      Mode <= (eMNT_READY + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMNT_READY THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMNT_READY * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMNT_READY THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMNT_READY) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Mode = eMNT_START: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMNT_START) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMNT_START - 1.0E-6) AND
      Mode <= (eMNT_START + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMNT_START THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMNT_START * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMNT_START THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMNT_START) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Mode = eBOAT_INIT: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eBOAT_INIT) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eBOAT_INIT - 1.0E-6) AND
      Mode <= (eBOAT_INIT + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eBOAT_INIT THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eBOAT_INIT * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eBOAT_INIT THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eBOAT_INIT) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Ctrl <> eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: IN = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(IN - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF IN >= (TRUE - 1.0E-6) AND
      IN <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF IN >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(IN * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF IN = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(IN - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: DX_INF_State_Module = eModule_Standby: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Standby) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Standby - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Standby + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Standby THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Standby * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Standby THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Standby) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: DX_SEQ_Physical_Boat_Elevator_Ctrl <> eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Physical_Boat_Elevator_Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Physical_Boat_Elevator_Ctrl >= (eRun - 1.0E-6) AND
      DX_SEQ_Physical_Boat_Elevator_Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Physical_Boat_Elevator_Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Physical_Boat_Elevator_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Physical_Boat_Elevator_Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Physical_Boat_Elevator_Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: SEQ_Interlock_Safety: 1833줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Interlock_Safety = 1833줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..400]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..400 >= 1 AND
      1..400 <= 10 THEN
       value := ARRAY[1..400];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..400, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..400 >= ARRAY_MIN AND 1..400 <= ARRAY_MAX THEN
       value := ARRAY[1..400];
   END_IF

예시:

❌ 위험: value := ARRAY[1..400]; // 범위 검사 없음!

✅ 안전: IF 1..400 >= 1 AND 1..400 <= 10 THEN
value := ARRAY[1..400];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..200]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..200 >= 1 AND
      1..200 <= 10 THEN
       value := ARRAY[1..200];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..200, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..200 >= ARRAY_MIN AND 1..200 <= ARRAY_MAX THEN
       value := ARRAY[1..200];
   END_IF

예시:

❌ 위험: value := ARRAY[1..200]; // 범위 검사 없음!

✅ 안전: IF 1..200 >= 1 AND 1..200 <= 10 THEN
value := ARRAY[1..200];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..100]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..100 >= 1 AND
      1..100 <= 10 THEN
       value := ARRAY[1..100];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..100, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..100 >= ARRAY_MIN AND 1..100 <= ARRAY_MAX THEN
       value := ARRAY[1..100];
   END_IF

예시:

❌ 위험: value := ARRAY[1..100]; // 범위 검사 없음!

✅ 안전: IF 1..100 >= 1 AND 1..100 <= 10 THEN
value := ARRAY[1..100];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..100]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..100 >= 1 AND
      1..100 <= 10 THEN
       value := ARRAY[1..100];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..100, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..100 >= ARRAY_MIN AND 1..100 <= ARRAY_MAX THEN
       value := ARRAY[1..100];
   END_IF

예시:

❌ 위험: value := ARRAY[1..100]; // 범위 검사 없음!

✅ 안전: IF 1..100 >= 1 AND 1..100 <= 10 THEN
value := ARRAY[1..100];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..10]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..10 >= 1 AND
      1..10 <= 10 THEN
       value := ARRAY[1..10];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..10, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..10 >= ARRAY_MIN AND 1..10 <= ARRAY_MAX THEN
       value := ARRAY[1..10];
   END_IF

예시:

❌ 위험: value := ARRAY[1..10]; // 범위 검사 없음!

✅ 안전: IF 1..10 >= 1 AND 1..10 <= 10 THEN
value := ARRAY[1..10];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..10]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..10 >= 1 AND
      1..10 <= 10 THEN
       value := ARRAY[1..10];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..10, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..10 >= ARRAY_MIN AND 1..10 <= ARRAY_MAX THEN
       value := ARRAY[1..10];
   END_IF

예시:

❌ 위험: value := ARRAY[1..10]; // 범위 검사 없음!

✅ 안전: IF 1..10 >= 1 AND 1..10 <= 10 THEN
value := ARRAY[1..10];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..cMAX_LineHeater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_LineHeater_Use_Zone >= 1 AND
      1..cMAX_LineHeater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_LineHeater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_LineHeater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_LineHeater_Use_Zone >= ARRAY_MIN AND 1..cMAX_LineHeater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_LineHeater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_LineHeater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_LineHeater_Use_Zone >= 1 AND 1..cMAX_LineHeater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_LineHeater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..cMAX_LineHeater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_LineHeater_Use_Zone >= 1 AND
      1..cMAX_LineHeater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_LineHeater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_LineHeater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_LineHeater_Use_Zone >= ARRAY_MIN AND 1..cMAX_LineHeater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_LineHeater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_LineHeater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_LineHeater_Use_Zone >= 1 AND 1..cMAX_LineHeater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_LineHeater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..cMAX_LineHeater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_LineHeater_Use_Zone >= 1 AND
      1..cMAX_LineHeater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_LineHeater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_LineHeater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_LineHeater_Use_Zone >= ARRAY_MIN AND 1..cMAX_LineHeater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_LineHeater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_LineHeater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_LineHeater_Use_Zone >= 1 AND 1..cMAX_LineHeater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_LineHeater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..cMAX_LineHeater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_LineHeater_Use_Zone >= 1 AND
      1..cMAX_LineHeater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_LineHeater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_LineHeater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_LineHeater_Use_Zone >= ARRAY_MIN AND 1..cMAX_LineHeater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_LineHeater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_LineHeater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_LineHeater_Use_Zone >= 1 AND 1..cMAX_LineHeater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_LineHeater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..cMAX_LineHeater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_LineHeater_Use_Zone >= 1 AND
      1..cMAX_LineHeater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_LineHeater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_LineHeater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_LineHeater_Use_Zone >= ARRAY_MIN AND 1..cMAX_LineHeater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_LineHeater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_LineHeater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_LineHeater_Use_Zone >= 1 AND 1..cMAX_LineHeater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_LineHeater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..cMAX_LineHeater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_LineHeater_Use_Zone >= 1 AND
      1..cMAX_LineHeater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_LineHeater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_LineHeater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_LineHeater_Use_Zone >= ARRAY_MIN AND 1..cMAX_LineHeater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_LineHeater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_LineHeater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_LineHeater_Use_Zone >= 1 AND 1..cMAX_LineHeater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_LineHeater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..10]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..10 >= 1 AND
      1..10 <= 10 THEN
       value := ARRAY[1..10];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..10, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..10 >= ARRAY_MIN AND 1..10 <= ARRAY_MAX THEN
       value := ARRAY[1..10];
   END_IF

예시:

❌ 위험: value := ARRAY[1..10]; // 범위 검사 없음!

✅ 안전: IF 1..10 >= 1 AND 1..10 <= 10 THEN
value := ARRAY[1..10];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..2]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..2 >= 1 AND
      1..2 <= 10 THEN
       value := ARRAY[1..2];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..2, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..2 >= ARRAY_MIN AND 1..2 <= ARRAY_MAX THEN
       value := ARRAY[1..2];
   END_IF

예시:

❌ 위험: value := ARRAY[1..2]; // 범위 검사 없음!

✅ 안전: IF 1..2 >= 1 AND 1..2 <= 10 THEN
value := ARRAY[1..2];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..100]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..100 >= 1 AND
      1..100 <= 10 THEN
       value := ARRAY[1..100];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..100, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..100 >= ARRAY_MIN AND 1..100 <= ARRAY_MAX THEN
       value := ARRAY[1..100];
   END_IF

예시:

❌ 위험: value := ARRAY[1..100]; // 범위 검사 없음!

✅ 안전: IF 1..100 >= 1 AND 1..100 <= 10 THEN
value := ARRAY[1..100];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..100]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..100 >= 1 AND
      1..100 <= 10 THEN
       value := ARRAY[1..100];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..100, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..100 >= ARRAY_MIN AND 1..100 <= ARRAY_MAX THEN
       value := ARRAY[1..100];
   END_IF

예시:

❌ 위험: value := ARRAY[1..100]; // 범위 검사 없음!

✅ 안전: IF 1..100 >= 1 AND 1..100 <= 10 THEN
value := ARRAY[1..100];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..5]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..5 >= 1 AND
      1..5 <= 10 THEN
       value := ARRAY[1..5];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..5, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..5 >= ARRAY_MIN AND 1..5 <= ARRAY_MAX THEN
       value := ARRAY[1..5];
   END_IF

예시:

❌ 위험: value := ARRAY[1..5]; // 범위 검사 없음!

✅ 안전: IF 1..5 >= 1 AND 1..5 <= 10 THEN
value := ARRAY[1..5];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: ARRAY[1..2]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..2 >= 1 AND
      1..2 <= 10 THEN
       value := ARRAY[1..2];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..2, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..2 >= ARRAY_MIN AND 1..2 <= ARRAY_MAX THEN
       value := ARRAY[1..2];
   END_IF

예시:

❌ 위험: value := ARRAY[1..2]; // 범위 검사 없음!

✅ 안전: IF 1..2 >= 1 AND 1..2 <= 10 THEN
value := ARRAY[1..2];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: SEQ_Interlock_Valve: 7395줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Interlock_Valve = 7395줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..100]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..100 >= 1 AND
      1..100 <= 10 THEN
       value := ARRAY[1..100];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..100, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..100 >= ARRAY_MIN AND 1..100 <= ARRAY_MAX THEN
       value := ARRAY[1..100];
   END_IF

예시:

❌ 위험: value := ARRAY[1..100]; // 범위 검사 없음!

✅ 안전: IF 1..100 >= 1 AND 1..100 <= 10 THEN
value := ARRAY[1..100];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..2]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..2 >= 1 AND
      1..2 <= 10 THEN
       value := ARRAY[1..2];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..2, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..2 >= ARRAY_MIN AND 1..2 <= ARRAY_MAX THEN
       value := ARRAY[1..2];
   END_IF

예시:

❌ 위험: value := ARRAY[1..2]; // 범위 검사 없음!

✅ 안전: IF 1..2 >= 1 AND 1..2 <= 10 THEN
value := ARRAY[1..2];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..3]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..3 >= 1 AND
      1..3 <= 10 THEN
       value := ARRAY[1..3];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..3, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..3 >= ARRAY_MIN AND 1..3 <= ARRAY_MAX THEN
       value := ARRAY[1..3];
   END_IF

예시:

❌ 위험: value := ARRAY[1..3]; // 범위 검사 없음!

✅ 안전: IF 1..3 >= 1 AND 1..3 <= 10 THEN
value := ARRAY[1..3];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..3]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..3 >= 1 AND
      1..3 <= 10 THEN
       value := ARRAY[1..3];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..3, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..3 >= ARRAY_MIN AND 1..3 <= ARRAY_MAX THEN
       value := ARRAY[1..3];
   END_IF

예시:

❌ 위험: value := ARRAY[1..3]; // 범위 검사 없음!

✅ 안전: IF 1..3 >= 1 AND 1..3 <= 10 THEN
value := ARRAY[1..3];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..5]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..5 >= 1 AND
      1..5 <= 10 THEN
       value := ARRAY[1..5];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..5, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..5 >= ARRAY_MIN AND 1..5 <= ARRAY_MAX THEN
       value := ARRAY[1..5];
   END_IF

예시:

❌ 위험: value := ARRAY[1..5]; // 범위 검사 없음!

✅ 안전: IF 1..5 >= 1 AND 1..5 <= 10 THEN
value := ARRAY[1..5];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..9]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..9 >= 1 AND
      1..9 <= 10 THEN
       value := ARRAY[1..9];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..9, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..9 >= ARRAY_MIN AND 1..9 <= ARRAY_MAX THEN
       value := ARRAY[1..9];
   END_IF

예시:

❌ 위험: value := ARRAY[1..9]; // 범위 검사 없음!

✅ 안전: IF 1..9 >= 1 AND 1..9 <= 10 THEN
value := ARRAY[1..9];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..9]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..9 >= 1 AND
      1..9 <= 10 THEN
       value := ARRAY[1..9];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..9, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..9 >= ARRAY_MIN AND 1..9 <= ARRAY_MAX THEN
       value := ARRAY[1..9];
   END_IF

예시:

❌ 위험: value := ARRAY[1..9]; // 범위 검사 없음!

✅ 안전: IF 1..9 >= 1 AND 1..9 <= 10 THEN
value := ARRAY[1..9];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..3]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..3 >= 1 AND
      1..3 <= 10 THEN
       value := ARRAY[1..3];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..3, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..3 >= ARRAY_MIN AND 1..3 <= ARRAY_MAX THEN
       value := ARRAY[1..3];
   END_IF

예시:

❌ 위험: value := ARRAY[1..3]; // 범위 검사 없음!

✅ 안전: IF 1..3 >= 1 AND 1..3 <= 10 THEN
value := ARRAY[1..3];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..3]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..3 >= 1 AND
      1..3 <= 10 THEN
       value := ARRAY[1..3];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..3, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..3 >= ARRAY_MIN AND 1..3 <= ARRAY_MAX THEN
       value := ARRAY[1..3];
   END_IF

예시:

❌ 위험: value := ARRAY[1..3]; // 범위 검사 없음!

✅ 안전: IF 1..3 >= 1 AND 1..3 <= 10 THEN
value := ARRAY[1..3];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..9]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..9 >= 1 AND
      1..9 <= 10 THEN
       value := ARRAY[1..9];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..9, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..9 >= ARRAY_MIN AND 1..9 <= ARRAY_MAX THEN
       value := ARRAY[1..9];
   END_IF

예시:

❌ 위험: value := ARRAY[1..9]; // 범위 검사 없음!

✅ 안전: IF 1..9 >= 1 AND 1..9 <= 10 THEN
value := ARRAY[1..9];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..6]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..6 >= 1 AND
      1..6 <= 10 THEN
       value := ARRAY[1..6];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..6, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..6 >= ARRAY_MIN AND 1..6 <= ARRAY_MAX THEN
       value := ARRAY[1..6];
   END_IF

예시:

❌ 위험: value := ARRAY[1..6]; // 범위 검사 없음!

✅ 안전: IF 1..6 >= 1 AND 1..6 <= 10 THEN
value := ARRAY[1..6];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..3]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..3 >= 1 AND
      1..3 <= 10 THEN
       value := ARRAY[1..3];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..3, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..3 >= ARRAY_MIN AND 1..3 <= ARRAY_MAX THEN
       value := ARRAY[1..3];
   END_IF

예시:

❌ 위험: value := ARRAY[1..3]; // 범위 검사 없음!

✅ 안전: IF 1..3 >= 1 AND 1..3 <= 10 THEN
value := ARRAY[1..3];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..3]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..3 >= 1 AND
      1..3 <= 10 THEN
       value := ARRAY[1..3];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..3, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..3 >= ARRAY_MIN AND 1..3 <= ARRAY_MAX THEN
       value := ARRAY[1..3];
   END_IF

예시:

❌ 위험: value := ARRAY[1..3]; // 범위 검사 없음!

✅ 안전: IF 1..3 >= 1 AND 1..3 <= 10 THEN
value := ARRAY[1..3];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..2]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..2 >= 1 AND
      1..2 <= 10 THEN
       value := ARRAY[1..2];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..2, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..2 >= ARRAY_MIN AND 1..2 <= ARRAY_MAX THEN
       value := ARRAY[1..2];
   END_IF

예시:

❌ 위험: value := ARRAY[1..2]; // 범위 검사 없음!

✅ 안전: IF 1..2 >= 1 AND 1..2 <= 10 THEN
value := ARRAY[1..2];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..12]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..12 >= 1 AND
      1..12 <= 10 THEN
       value := ARRAY[1..12];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..12, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..12 >= ARRAY_MIN AND 1..12 <= ARRAY_MAX THEN
       value := ARRAY[1..12];
   END_IF

예시:

❌ 위험: value := ARRAY[1..12]; // 범위 검사 없음!

✅ 안전: IF 1..12 >= 1 AND 1..12 <= 10 THEN
value := ARRAY[1..12];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..26]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..26 >= 1 AND
      1..26 <= 10 THEN
       value := ARRAY[1..26];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..26, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..26 >= ARRAY_MIN AND 1..26 <= ARRAY_MAX THEN
       value := ARRAY[1..26];
   END_IF

예시:

❌ 위험: value := ARRAY[1..26]; // 범위 검사 없음!

✅ 안전: IF 1..26 >= 1 AND 1..26 <= 10 THEN
value := ARRAY[1..26];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..9]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..9 >= 1 AND
      1..9 <= 10 THEN
       value := ARRAY[1..9];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..9, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..9 >= ARRAY_MIN AND 1..9 <= ARRAY_MAX THEN
       value := ARRAY[1..9];
   END_IF

예시:

❌ 위험: value := ARRAY[1..9]; // 범위 검사 없음!

✅ 안전: IF 1..9 >= 1 AND 1..9 <= 10 THEN
value := ARRAY[1..9];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..13]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..13 >= 1 AND
      1..13 <= 10 THEN
       value := ARRAY[1..13];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..13, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..13 >= ARRAY_MIN AND 1..13 <= ARRAY_MAX THEN
       value := ARRAY[1..13];
   END_IF

예시:

❌ 위험: value := ARRAY[1..13]; // 범위 검사 없음!

✅ 안전: IF 1..13 >= 1 AND 1..13 <= 10 THEN
value := ARRAY[1..13];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..2]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..2 >= 1 AND
      1..2 <= 10 THEN
       value := ARRAY[1..2];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..2, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..2 >= ARRAY_MIN AND 1..2 <= ARRAY_MAX THEN
       value := ARRAY[1..2];
   END_IF

예시:

❌ 위험: value := ARRAY[1..2]; // 범위 검사 없음!

✅ 안전: IF 1..2 >= 1 AND 1..2 <= 10 THEN
value := ARRAY[1..2];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..2]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..2 >= 1 AND
      1..2 <= 10 THEN
       value := ARRAY[1..2];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..2, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..2 >= ARRAY_MIN AND 1..2 <= ARRAY_MAX THEN
       value := ARRAY[1..2];
   END_IF

예시:

❌ 위험: value := ARRAY[1..2]; // 범위 검사 없음!

✅ 안전: IF 1..2 >= 1 AND 1..2 <= 10 THEN
value := ARRAY[1..2];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1.. 2]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1.. 2 >= 1 AND
      1.. 2 <= 10 THEN
       value := ARRAY[1.. 2];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1.. 2, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1.. 2 >= ARRAY_MIN AND 1.. 2 <= ARRAY_MAX THEN
       value := ARRAY[1.. 2];
   END_IF

예시:

❌ 위험: value := ARRAY[1.. 2]; // 범위 검사 없음!

✅ 안전: IF 1.. 2 >= 1 AND 1.. 2 <= 10 THEN
value := ARRAY[1.. 2];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: ARRAY[1..cMAX_FFU]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_FFU >= 1 AND
      1..cMAX_FFU <= 10 THEN
       value := ARRAY[1..cMAX_FFU];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_FFU, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_FFU >= ARRAY_MIN AND 1..cMAX_FFU <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_FFU];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_FFU]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_FFU >= 1 AND 1..cMAX_FFU <= 10 THEN
value := ARRAY[1..cMAX_FFU];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: SEQ_Physical_APC: 1178줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Physical_APC = 1178줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: DX_INF_State_Module <> eModule_Disable: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Disable - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Disable + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Disable THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Disable * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Disable THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: old_Mode <> Mode: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(old_Mode - Mode) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF old_Mode >= (Mode - 1.0E-6) AND
      old_Mode <= (Mode + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF old_Mode >= Mode THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(old_Mode * 10.0);
   intTarget := REAL_TO_DINT(Mode * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF old_Mode = Mode THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(old_Mode - Mode) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Mode <> eAPC_HOMING: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAPC_HOMING) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAPC_HOMING - 1.0E-6) AND
      Mode <= (eAPC_HOMING + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAPC_HOMING THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAPC_HOMING * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAPC_HOMING THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAPC_HOMING) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Mode <> eAPC_VG_CAL_RCP: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAPC_VG_CAL_RCP) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAPC_VG_CAL_RCP - 1.0E-6) AND
      Mode <= (eAPC_VG_CAL_RCP + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAPC_VG_CAL_RCP THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAPC_VG_CAL_RCP * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAPC_VG_CAL_RCP THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAPC_VG_CAL_RCP) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Mode <> eAPC_VG_CAL_MNT: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAPC_VG_CAL_MNT) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAPC_VG_CAL_MNT - 1.0E-6) AND
      Mode <= (eAPC_VG_CAL_MNT + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAPC_VG_CAL_MNT THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAPC_VG_CAL_MNT * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAPC_VG_CAL_MNT THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAPC_VG_CAL_MNT) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Mode = eAPC_CLOSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAPC_CLOSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAPC_CLOSE - 1.0E-6) AND
      Mode <= (eAPC_CLOSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAPC_CLOSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAPC_CLOSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAPC_CLOSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAPC_CLOSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Mode = eAPC_OPEN: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAPC_OPEN) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAPC_OPEN - 1.0E-6) AND
      Mode <= (eAPC_OPEN + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAPC_OPEN THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAPC_OPEN * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAPC_OPEN THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAPC_OPEN) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Mode = eAPC_SLOW: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAPC_SLOW) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAPC_SLOW - 1.0E-6) AND
      Mode <= (eAPC_SLOW + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAPC_SLOW THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAPC_SLOW * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAPC_SLOW THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAPC_SLOW) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Mode = eAPC_POSITION: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAPC_POSITION) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAPC_POSITION - 1.0E-6) AND
      Mode <= (eAPC_POSITION + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAPC_POSITION THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAPC_POSITION * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAPC_POSITION THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAPC_POSITION) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Mode = eAPC_PRESSURE1: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAPC_PRESSURE1) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAPC_PRESSURE1 - 1.0E-6) AND
      Mode <= (eAPC_PRESSURE1 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAPC_PRESSURE1 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAPC_PRESSURE1 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAPC_PRESSURE1 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAPC_PRESSURE1) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Mode = eAPC_PRESSURE2: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAPC_PRESSURE2) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAPC_PRESSURE2 - 1.0E-6) AND
      Mode <= (eAPC_PRESSURE2 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAPC_PRESSURE2 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAPC_PRESSURE2 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAPC_PRESSURE2 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAPC_PRESSURE2) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Mode = eAPC_LEAKCHECK1: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAPC_LEAKCHECK1) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAPC_LEAKCHECK1 - 1.0E-6) AND
      Mode <= (eAPC_LEAKCHECK1 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAPC_LEAKCHECK1 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAPC_LEAKCHECK1 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAPC_LEAKCHECK1 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAPC_LEAKCHECK1) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Mode = eAPC_LEAKCHECK2: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAPC_LEAKCHECK2) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAPC_LEAKCHECK2 - 1.0E-6) AND
      Mode <= (eAPC_LEAKCHECK2 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAPC_LEAKCHECK2 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAPC_LEAKCHECK2 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAPC_LEAKCHECK2 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAPC_LEAKCHECK2) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Mode = eAPC_LEAKCHECK3: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAPC_LEAKCHECK3) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAPC_LEAKCHECK3 - 1.0E-6) AND
      Mode <= (eAPC_LEAKCHECK3 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAPC_LEAKCHECK3 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAPC_LEAKCHECK3 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAPC_LEAKCHECK3 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAPC_LEAKCHECK3) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Mode = eAPC_HOMING: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAPC_HOMING) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAPC_HOMING - 1.0E-6) AND
      Mode <= (eAPC_HOMING + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAPC_HOMING THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAPC_HOMING * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAPC_HOMING THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAPC_HOMING) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Mode = eAPC_VG_CAL_RCP: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAPC_VG_CAL_RCP) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAPC_VG_CAL_RCP - 1.0E-6) AND
      Mode <= (eAPC_VG_CAL_RCP + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAPC_VG_CAL_RCP THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAPC_VG_CAL_RCP * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAPC_VG_CAL_RCP THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAPC_VG_CAL_RCP) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Mode = eAPC_VG_CAL_MNT: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eAPC_VG_CAL_MNT) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eAPC_VG_CAL_MNT - 1.0E-6) AND
      Mode <= (eAPC_VG_CAL_MNT + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eAPC_VG_CAL_MNT THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eAPC_VG_CAL_MNT * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eAPC_VG_CAL_MNT THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eAPC_VG_CAL_MNT) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Ctrl <> eAborted: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAborted) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAborted - 1.0E-6) AND
      Ctrl <= (eAborted + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAborted THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAborted * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAborted THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAborted) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: DI_APC_Mode <> edAPC_Close: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_APC_Mode - edAPC_Close) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_APC_Mode >= (edAPC_Close - 1.0E-6) AND
      DI_APC_Mode <= (edAPC_Close + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_APC_Mode >= edAPC_Close THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_APC_Mode * 10.0);
   intTarget := REAL_TO_DINT(edAPC_Close * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_APC_Mode = edAPC_Close THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_APC_Mode - edAPC_Close) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Ctrl = eAborted: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAborted) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAborted - 1.0E-6) AND
      Ctrl <= (eAborted + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAborted THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAborted * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAborted THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAborted) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: DI_APC_Mode = edAPC_Close: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_APC_Mode - edAPC_Close) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_APC_Mode >= (edAPC_Close - 1.0E-6) AND
      DI_APC_Mode <= (edAPC_Close + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_APC_Mode >= edAPC_Close THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_APC_Mode * 10.0);
   intTarget := REAL_TO_DINT(edAPC_Close * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_APC_Mode = edAPC_Close THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_APC_Mode - edAPC_Close) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: Ctrl = eIdle: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eIdle) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eIdle - 1.0E-6) AND
      Ctrl <= (eIdle + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eIdle THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eIdle * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eIdle THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eIdle) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: SEQ_Physical_Boat_Elevator: 2576줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Physical_Boat_Elevator = 2576줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: DX_INF_State_Module <> eModule_Disable: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Disable - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Disable + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Disable THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Disable * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Disable THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: Mode = eBOAT_ELEVATOR_STOP: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eBOAT_ELEVATOR_STOP) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eBOAT_ELEVATOR_STOP - 1.0E-6) AND
      Mode <= (eBOAT_ELEVATOR_STOP + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eBOAT_ELEVATOR_STOP THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eBOAT_ELEVATOR_STOP * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eBOAT_ELEVATOR_STOP THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eBOAT_ELEVATOR_STOP) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: Mode = eBOAT_ELEVATOR_INIT: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eBOAT_ELEVATOR_INIT) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eBOAT_ELEVATOR_INIT - 1.0E-6) AND
      Mode <= (eBOAT_ELEVATOR_INIT + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eBOAT_ELEVATOR_INIT THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eBOAT_ELEVATOR_INIT * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eBOAT_ELEVATOR_INIT THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eBOAT_ELEVATOR_INIT) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: Mode = eBOAT_ELEVATOR_UP: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eBOAT_ELEVATOR_UP) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eBOAT_ELEVATOR_UP - 1.0E-6) AND
      Mode <= (eBOAT_ELEVATOR_UP + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eBOAT_ELEVATOR_UP THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eBOAT_ELEVATOR_UP * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eBOAT_ELEVATOR_UP THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eBOAT_ELEVATOR_UP) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: Mode = eBOAT_ELEVATOR_HOME: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eBOAT_ELEVATOR_HOME) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eBOAT_ELEVATOR_HOME - 1.0E-6) AND
      Mode <= (eBOAT_ELEVATOR_HOME + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eBOAT_ELEVATOR_HOME THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eBOAT_ELEVATOR_HOME * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eBOAT_ELEVATOR_HOME THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eBOAT_ELEVATOR_HOME) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: Mode = eBOAT_ELEVATOR_DOWN: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eBOAT_ELEVATOR_DOWN) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eBOAT_ELEVATOR_DOWN - 1.0E-6) AND
      Mode <= (eBOAT_ELEVATOR_DOWN + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eBOAT_ELEVATOR_DOWN THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eBOAT_ELEVATOR_DOWN * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eBOAT_ELEVATOR_DOWN THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eBOAT_ELEVATOR_DOWN) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: Mode = eBOAT_ELEVATOR_MAINT: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eBOAT_ELEVATOR_MAINT) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eBOAT_ELEVATOR_MAINT - 1.0E-6) AND
      Mode <= (eBOAT_ELEVATOR_MAINT + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eBOAT_ELEVATOR_MAINT THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eBOAT_ELEVATOR_MAINT * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eBOAT_ELEVATOR_MAINT THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eBOAT_ELEVATOR_MAINT) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: Mode = eBOAT_ELEVATOR_STOP: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eBOAT_ELEVATOR_STOP) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eBOAT_ELEVATOR_STOP - 1.0E-6) AND
      Mode <= (eBOAT_ELEVATOR_STOP + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eBOAT_ELEVATOR_STOP THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eBOAT_ELEVATOR_STOP * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eBOAT_ELEVATOR_STOP THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eBOAT_ELEVATOR_STOP) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: Mode = eBOAT_ELEVATOR_Reset: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eBOAT_ELEVATOR_Reset) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eBOAT_ELEVATOR_Reset - 1.0E-6) AND
      Mode <= (eBOAT_ELEVATOR_Reset + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eBOAT_ELEVATOR_Reset THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eBOAT_ELEVATOR_Reset * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eBOAT_ELEVATOR_Reset THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eBOAT_ELEVATOR_Reset) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: DX_SEQ_Driver_Boat_Elevator_Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Driver_Boat_Elevator_Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Driver_Boat_Elevator_Ctrl >= (eRun - 1.0E-6) AND
      DX_SEQ_Driver_Boat_Elevator_Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Driver_Boat_Elevator_Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Driver_Boat_Elevator_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Driver_Boat_Elevator_Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Driver_Boat_Elevator_Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: DX_SEQ_Driver_Boat_Elevator_Mode <> edBOAT_ELEVATOR_Stop: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Driver_Boat_Elevator_Mode - edBOAT_ELEVATOR_Stop) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Driver_Boat_Elevator_Mode >= (edBOAT_ELEVATOR_Stop - 1.0E-6) AND
      DX_SEQ_Driver_Boat_Elevator_Mode <= (edBOAT_ELEVATOR_Stop + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Driver_Boat_Elevator_Mode >= edBOAT_ELEVATOR_Stop THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Driver_Boat_Elevator_Mode * 10.0);
   intTarget := REAL_TO_DINT(edBOAT_ELEVATOR_Stop * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Driver_Boat_Elevator_Mode = edBOAT_ELEVATOR_Stop THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Driver_Boat_Elevator_Mode - edBOAT_ELEVATOR_Stop) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: DI_LOADINGAREA_FFU_HEATER_OVERTEMP = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_LOADINGAREA_FFU_HEATER_OVERTEMP - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_LOADINGAREA_FFU_HEATER_OVERTEMP >= (FALSE - 1.0E-6) AND
      DI_LOADINGAREA_FFU_HEATER_OVERTEMP <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_LOADINGAREA_FFU_HEATER_OVERTEMP >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_LOADINGAREA_FFU_HEATER_OVERTEMP * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_LOADINGAREA_FFU_HEATER_OVERTEMP = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_LOADINGAREA_FFU_HEATER_OVERTEMP - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: mDI16_06_FFU_EXHAUST_LOW = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(mDI16_06_FFU_EXHAUST_LOW - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF mDI16_06_FFU_EXHAUST_LOW >= (FALSE - 1.0E-6) AND
      mDI16_06_FFU_EXHAUST_LOW <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF mDI16_06_FFU_EXHAUST_LOW >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(mDI16_06_FFU_EXHAUST_LOW * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF mDI16_06_FFU_EXHAUST_LOW = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(mDI16_06_FFU_EXHAUST_LOW - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: Timeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timeout <> NULL THEN
       value := Timeout^;
       // 또는 Timeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timeout) THEN
       value := Timeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timeout := ADR(targetVariable);
   IF Timeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timeout^; // NULL 체크 없음!
value := Timeout.member; // NULL 체크 없음!

✅ 안전: IF Timeout <> NULL THEN
value := Timeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timeout) THEN
value := Timeout.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: Sleep: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Sleep <> NULL THEN
       value := Sleep^;
       // 또는 Sleep.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Sleep');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Sleep) THEN
       value := Sleep.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Sleep := ADR(targetVariable);
   IF Sleep = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Sleep = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Sleep^; // NULL 체크 없음!
value := Sleep.member; // NULL 체크 없음!

✅ 안전: IF Sleep <> NULL THEN
value := Sleep^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Sleep) THEN
value := Sleep.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: Sleep: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Sleep <> NULL THEN
       value := Sleep^;
       // 또는 Sleep.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Sleep');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Sleep) THEN
       value := Sleep.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Sleep := ADR(targetVariable);
   IF Sleep = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Sleep = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Sleep^; // NULL 체크 없음!
value := Sleep.member; // NULL 체크 없음!

✅ 안전: IF Sleep <> NULL THEN
value := Sleep^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Sleep) THEN
value := Sleep.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: SEQ_Physical_Boat_Rotation: 473줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Physical_Boat_Rotation = 473줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: DX_INF_State_Module <> eModule_Disable: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Disable - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Disable + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Disable THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Disable * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Disable THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: Mode = eBOAT_ROTATION_OFF: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eBOAT_ROTATION_OFF) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eBOAT_ROTATION_OFF - 1.0E-6) AND
      Mode <= (eBOAT_ROTATION_OFF + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eBOAT_ROTATION_OFF THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eBOAT_ROTATION_OFF * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eBOAT_ROTATION_OFF THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eBOAT_ROTATION_OFF) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: Mode = eBOAT_ROTATION_INIT: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eBOAT_ROTATION_INIT) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eBOAT_ROTATION_INIT - 1.0E-6) AND
      Mode <= (eBOAT_ROTATION_INIT + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eBOAT_ROTATION_INIT THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eBOAT_ROTATION_INIT * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eBOAT_ROTATION_INIT THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eBOAT_ROTATION_INIT) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: Mode = eBOAT_ROTATION_OFF: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eBOAT_ROTATION_OFF) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eBOAT_ROTATION_OFF - 1.0E-6) AND
      Mode <= (eBOAT_ROTATION_OFF + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eBOAT_ROTATION_OFF THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eBOAT_ROTATION_OFF * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eBOAT_ROTATION_OFF THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eBOAT_ROTATION_OFF) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: Mode = eBOAT_ROTATION_ON: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eBOAT_ROTATION_ON) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eBOAT_ROTATION_ON - 1.0E-6) AND
      Mode <= (eBOAT_ROTATION_ON + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eBOAT_ROTATION_ON THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eBOAT_ROTATION_ON * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eBOAT_ROTATION_ON THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eBOAT_ROTATION_ON) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: Mode = eBOAT_ROTATION_OFF_HOME: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eBOAT_ROTATION_OFF_HOME) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eBOAT_ROTATION_OFF_HOME - 1.0E-6) AND
      Mode <= (eBOAT_ROTATION_OFF_HOME + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eBOAT_ROTATION_OFF_HOME THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eBOAT_ROTATION_OFF_HOME * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eBOAT_ROTATION_OFF_HOME THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eBOAT_ROTATION_OFF_HOME) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: Mode = eBOAT_ROTATION_Reset: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eBOAT_ROTATION_Reset) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eBOAT_ROTATION_Reset - 1.0E-6) AND
      Mode <= (eBOAT_ROTATION_Reset + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eBOAT_ROTATION_Reset THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eBOAT_ROTATION_Reset * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eBOAT_ROTATION_Reset THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eBOAT_ROTATION_Reset) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: DX_SEQ_Driver_Boat_Rotation_Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Driver_Boat_Rotation_Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Driver_Boat_Rotation_Ctrl >= (eRun - 1.0E-6) AND
      DX_SEQ_Driver_Boat_Rotation_Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Driver_Boat_Rotation_Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Driver_Boat_Rotation_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Driver_Boat_Rotation_Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Driver_Boat_Rotation_Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: DI_WTR_ITLK_BOAT_MOVE_AVAILABLE = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_WTR_ITLK_BOAT_MOVE_AVAILABLE - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_WTR_ITLK_BOAT_MOVE_AVAILABLE >= (FALSE - 1.0E-6) AND
      DI_WTR_ITLK_BOAT_MOVE_AVAILABLE <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_WTR_ITLK_BOAT_MOVE_AVAILABLE >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_WTR_ITLK_BOAT_MOVE_AVAILABLE * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_WTR_ITLK_BOAT_MOVE_AVAILABLE = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_WTR_ITLK_BOAT_MOVE_AVAILABLE - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: DI_RotateStatus = eState_Boat_Alarm: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_RotateStatus - eState_Boat_Alarm) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_RotateStatus >= (eState_Boat_Alarm - 1.0E-6) AND
      DI_RotateStatus <= (eState_Boat_Alarm + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_RotateStatus >= eState_Boat_Alarm THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_RotateStatus * 10.0);
   intTarget := REAL_TO_DINT(eState_Boat_Alarm * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_RotateStatus = eState_Boat_Alarm THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_RotateStatus - eState_Boat_Alarm) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: DI_TCPIP_BR_Alarm <> FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_TCPIP_BR_Alarm - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_TCPIP_BR_Alarm >= (FALSE - 1.0E-6) AND
      DI_TCPIP_BR_Alarm <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_TCPIP_BR_Alarm >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_TCPIP_BR_Alarm * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_TCPIP_BR_Alarm = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_TCPIP_BR_Alarm - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: DI_BOAT_ROTATOR_HOME_POSITION = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_BOAT_ROTATOR_HOME_POSITION - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_BOAT_ROTATOR_HOME_POSITION >= (TRUE - 1.0E-6) AND
      DI_BOAT_ROTATOR_HOME_POSITION <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_BOAT_ROTATOR_HOME_POSITION >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_BOAT_ROTATOR_HOME_POSITION * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_BOAT_ROTATOR_HOME_POSITION = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_BOAT_ROTATOR_HOME_POSITION - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: AI_Rotate_Current_Position = AI_Rotate_Home_Position: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(AI_Rotate_Current_Position - AI_Rotate_Home_Position) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF AI_Rotate_Current_Position >= (AI_Rotate_Home_Position - 1.0E-6) AND
      AI_Rotate_Current_Position <= (AI_Rotate_Home_Position + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF AI_Rotate_Current_Position >= AI_Rotate_Home_Position THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(AI_Rotate_Current_Position * 10.0);
   intTarget := REAL_TO_DINT(AI_Rotate_Home_Position * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF AI_Rotate_Current_Position = AI_Rotate_Home_Position THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(AI_Rotate_Current_Position - AI_Rotate_Home_Position) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: DI_RotateStatus = eState_Boat_StanBy: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_RotateStatus - eState_Boat_StanBy) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_RotateStatus >= (eState_Boat_StanBy - 1.0E-6) AND
      DI_RotateStatus <= (eState_Boat_StanBy + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_RotateStatus >= eState_Boat_StanBy THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_RotateStatus * 10.0);
   intTarget := REAL_TO_DINT(eState_Boat_StanBy * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_RotateStatus = eState_Boat_StanBy THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_RotateStatus - eState_Boat_StanBy) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: DX_SEQ_Driver_Boat_Rotation_Ctrl = eIdle: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Driver_Boat_Rotation_Ctrl - eIdle) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Driver_Boat_Rotation_Ctrl >= (eIdle - 1.0E-6) AND
      DX_SEQ_Driver_Boat_Rotation_Ctrl <= (eIdle + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Driver_Boat_Rotation_Ctrl >= eIdle THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Driver_Boat_Rotation_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eIdle * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Driver_Boat_Rotation_Ctrl = eIdle THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Driver_Boat_Rotation_Ctrl - eIdle) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: DX_SEQ_Driver_Boat_Rotation_Ctrl = eAborted: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Driver_Boat_Rotation_Ctrl - eAborted) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Driver_Boat_Rotation_Ctrl >= (eAborted - 1.0E-6) AND
      DX_SEQ_Driver_Boat_Rotation_Ctrl <= (eAborted + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Driver_Boat_Rotation_Ctrl >= eAborted THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Driver_Boat_Rotation_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAborted * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Driver_Boat_Rotation_Ctrl = eAborted THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Driver_Boat_Rotation_Ctrl - eAborted) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: DI_RotateStatus <> eState_Boat_Init_Running: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_RotateStatus - eState_Boat_Init_Running) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_RotateStatus >= (eState_Boat_Init_Running - 1.0E-6) AND
      DI_RotateStatus <= (eState_Boat_Init_Running + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_RotateStatus >= eState_Boat_Init_Running THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_RotateStatus * 10.0);
   intTarget := REAL_TO_DINT(eState_Boat_Init_Running * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_RotateStatus = eState_Boat_Init_Running THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_RotateStatus - eState_Boat_Init_Running) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: DI_RotateStatus <> eState_Boat_Running: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_RotateStatus - eState_Boat_Running) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_RotateStatus >= (eState_Boat_Running - 1.0E-6) AND
      DI_RotateStatus <= (eState_Boat_Running + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_RotateStatus >= eState_Boat_Running THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_RotateStatus * 10.0);
   intTarget := REAL_TO_DINT(eState_Boat_Running * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_RotateStatus = eState_Boat_Running THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_RotateStatus - eState_Boat_Running) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: DX_SEQ_Driver_Boat_Rotation_Ctrl = eIdle: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Driver_Boat_Rotation_Ctrl - eIdle) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Driver_Boat_Rotation_Ctrl >= (eIdle - 1.0E-6) AND
      DX_SEQ_Driver_Boat_Rotation_Ctrl <= (eIdle + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Driver_Boat_Rotation_Ctrl >= eIdle THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Driver_Boat_Rotation_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eIdle * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Driver_Boat_Rotation_Ctrl = eIdle THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Driver_Boat_Rotation_Ctrl - eIdle) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: DX_SEQ_Driver_Boat_Rotation_Ctrl = eAborted: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Driver_Boat_Rotation_Ctrl - eAborted) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Driver_Boat_Rotation_Ctrl >= (eAborted - 1.0E-6) AND
      DX_SEQ_Driver_Boat_Rotation_Ctrl <= (eAborted + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Driver_Boat_Rotation_Ctrl >= eAborted THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Driver_Boat_Rotation_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAborted * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Driver_Boat_Rotation_Ctrl = eAborted THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Driver_Boat_Rotation_Ctrl - eAborted) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: Timeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timeout <> NULL THEN
       value := Timeout^;
       // 또는 Timeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timeout) THEN
       value := Timeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timeout := ADR(targetVariable);
   IF Timeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timeout^; // NULL 체크 없음!
value := Timeout.member; // NULL 체크 없음!

✅ 안전: IF Timeout <> NULL THEN
value := Timeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timeout) THEN
value := Timeout.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: SEQ_Physical_FRPTV: 532줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Physical_FRPTV = 532줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: DX_INF_State_Module <> eModule_Disable: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Disable - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Disable + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Disable THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Disable * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Disable THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: Mode = eFRPTV_CMD_TDC: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eFRPTV_CMD_TDC) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eFRPTV_CMD_TDC - 1.0E-6) AND
      Mode <= (eFRPTV_CMD_TDC + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eFRPTV_CMD_TDC THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eFRPTV_CMD_TDC * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eFRPTV_CMD_TDC THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eFRPTV_CMD_TDC) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: oldMode <> Mode: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(oldMode - Mode) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF oldMode >= (Mode - 1.0E-6) AND
      oldMode <= (Mode + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF oldMode >= Mode THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(oldMode * 10.0);
   intTarget := REAL_TO_DINT(Mode * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF oldMode = Mode THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(oldMode - Mode) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: Mode = eFRPTV_CMD_STOP: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eFRPTV_CMD_STOP) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eFRPTV_CMD_STOP - 1.0E-6) AND
      Mode <= (eFRPTV_CMD_STOP + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eFRPTV_CMD_STOP THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eFRPTV_CMD_STOP * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eFRPTV_CMD_STOP THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eFRPTV_CMD_STOP) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: Mode = eFRPTV_CMD_SET: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eFRPTV_CMD_SET) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eFRPTV_CMD_SET - 1.0E-6) AND
      Mode <= (eFRPTV_CMD_SET + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eFRPTV_CMD_SET THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eFRPTV_CMD_SET * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eFRPTV_CMD_SET THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eFRPTV_CMD_SET) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: Mode = eFRPTV_CMD_TDC: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eFRPTV_CMD_TDC) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eFRPTV_CMD_TDC - 1.0E-6) AND
      Mode <= (eFRPTV_CMD_TDC + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eFRPTV_CMD_TDC THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eFRPTV_CMD_TDC * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eFRPTV_CMD_TDC THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eFRPTV_CMD_TDC) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: DX_CFG_FRPTV_Abort_Action = eClose: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_CFG_FRPTV_Abort_Action - eClose) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_CFG_FRPTV_Abort_Action >= (eClose - 1.0E-6) AND
      DX_CFG_FRPTV_Abort_Action <= (eClose + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_CFG_FRPTV_Abort_Action >= eClose THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_CFG_FRPTV_Abort_Action * 10.0);
   intTarget := REAL_TO_DINT(eClose * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_CFG_FRPTV_Abort_Action = eClose THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_CFG_FRPTV_Abort_Action - eClose) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: DX_TV_TDC_MODE_ON = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_TV_TDC_MODE_ON - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_TV_TDC_MODE_ON >= (TRUE - 1.0E-6) AND
      DX_TV_TDC_MODE_ON <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_TV_TDC_MODE_ON >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_TV_TDC_MODE_ON * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_TV_TDC_MODE_ON = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_TV_TDC_MODE_ON - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: DO_Heater_Command = eHeaterCommand_Idle: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DO_Heater_Command - eHeaterCommand_Idle) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DO_Heater_Command >= (eHeaterCommand_Idle - 1.0E-6) AND
      DO_Heater_Command <= (eHeaterCommand_Idle + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DO_Heater_Command >= eHeaterCommand_Idle THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DO_Heater_Command * 10.0);
   intTarget := REAL_TO_DINT(eHeaterCommand_Idle * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DO_Heater_Command = eHeaterCommand_Idle THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DO_Heater_Command - eHeaterCommand_Idle) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: DO_Heater_Command = eHeaterCommand_Idle: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DO_Heater_Command - eHeaterCommand_Idle) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DO_Heater_Command >= (eHeaterCommand_Idle - 1.0E-6) AND
      DO_Heater_Command <= (eHeaterCommand_Idle + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DO_Heater_Command >= eHeaterCommand_Idle THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DO_Heater_Command * 10.0);
   intTarget := REAL_TO_DINT(eHeaterCommand_Idle * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DO_Heater_Command = eHeaterCommand_Idle THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DO_Heater_Command - eHeaterCommand_Idle) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: DI_FRP_INVERTER_ALARM = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_FRP_INVERTER_ALARM - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_FRP_INVERTER_ALARM >= (TRUE - 1.0E-6) AND
      DI_FRP_INVERTER_ALARM <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_FRP_INVERTER_ALARM >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_FRP_INVERTER_ALARM * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_FRP_INVERTER_ALARM = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_FRP_INVERTER_ALARM - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: DI_AV54_OPEN = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_AV54_OPEN - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_AV54_OPEN >= (TRUE - 1.0E-6) AND
      DI_AV54_OPEN <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_AV54_OPEN >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_AV54_OPEN * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_AV54_OPEN = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_AV54_OPEN - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: DI_AV54_CLOSE = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_AV54_CLOSE - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_AV54_CLOSE >= (FALSE - 1.0E-6) AND
      DI_AV54_CLOSE <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_AV54_CLOSE >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_AV54_CLOSE * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_AV54_CLOSE = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_AV54_CLOSE - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: Q = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (FALSE - 1.0E-6) AND
      Q <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: DI_AV54_OPEN = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_AV54_OPEN - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_AV54_OPEN >= (FALSE - 1.0E-6) AND
      DI_AV54_OPEN <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_AV54_OPEN >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_AV54_OPEN * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_AV54_OPEN = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_AV54_OPEN - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: DI_AV54_CLOSE = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_AV54_CLOSE - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_AV54_CLOSE >= (TRUE - 1.0E-6) AND
      DI_AV54_CLOSE <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_AV54_CLOSE >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_AV54_CLOSE * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_AV54_CLOSE = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_AV54_CLOSE - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: AO_TV_SET_POSITION[loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF loop >= 1 AND
      loop <= 10 THEN
       value := AO_TV_SET_POSITION[loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, loop, 10);
   value := AO_TV_SET_POSITION[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF loop >= ARRAY_MIN AND loop <= ARRAY_MAX THEN
       value := AO_TV_SET_POSITION[loop];
   END_IF

예시:

❌ 위험: value := AO_TV_SET_POSITION[loop]; // 범위 검사 없음!

✅ 안전: IF loop >= 1 AND loop <= 10 THEN
value := AO_TV_SET_POSITION[loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_GFC.TcPOU:1

설명: SEQ_Physical_GFC: 190줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Physical_GFC = 190줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_GFC.TcPOU:1

설명: DI_GFC_MANUAL_SWITCH_ON = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_GFC_MANUAL_SWITCH_ON - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_GFC_MANUAL_SWITCH_ON >= (TRUE - 1.0E-6) AND
      DI_GFC_MANUAL_SWITCH_ON <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_GFC_MANUAL_SWITCH_ON >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_GFC_MANUAL_SWITCH_ON * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_GFC_MANUAL_SWITCH_ON = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_GFC_MANUAL_SWITCH_ON - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_GFC.TcPOU:1

설명: DI_GFC_MANUAL_SWITCH_ON = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_GFC_MANUAL_SWITCH_ON - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_GFC_MANUAL_SWITCH_ON >= (TRUE - 1.0E-6) AND
      DI_GFC_MANUAL_SWITCH_ON <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_GFC_MANUAL_SWITCH_ON >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_GFC_MANUAL_SWITCH_ON * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_GFC_MANUAL_SWITCH_ON = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_GFC_MANUAL_SWITCH_ON - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_GFC.TcPOU:1

설명: mDO250_00_GFC_MANUAL_LAMP_ON = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(mDO250_00_GFC_MANUAL_LAMP_ON - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF mDO250_00_GFC_MANUAL_LAMP_ON >= (FALSE - 1.0E-6) AND
      mDO250_00_GFC_MANUAL_LAMP_ON <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF mDO250_00_GFC_MANUAL_LAMP_ON >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(mDO250_00_GFC_MANUAL_LAMP_ON * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF mDO250_00_GFC_MANUAL_LAMP_ON = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(mDO250_00_GFC_MANUAL_LAMP_ON - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_GFC.TcPOU:1

설명: mDI250_02_GFC_SET_SWITCH_ON = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(mDI250_02_GFC_SET_SWITCH_ON - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF mDI250_02_GFC_SET_SWITCH_ON >= (TRUE - 1.0E-6) AND
      mDI250_02_GFC_SET_SWITCH_ON <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF mDI250_02_GFC_SET_SWITCH_ON >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(mDI250_02_GFC_SET_SWITCH_ON * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF mDI250_02_GFC_SET_SWITCH_ON = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(mDI250_02_GFC_SET_SWITCH_ON - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: Timeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timeout <> NULL THEN
       value := Timeout^;
       // 또는 Timeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timeout) THEN
       value := Timeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timeout := ADR(targetVariable);
   IF Timeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timeout^; // NULL 체크 없음!
value := Timeout.member; // NULL 체크 없음!

✅ 안전: IF Timeout <> NULL THEN
value := Timeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timeout) THEN
value := Timeout.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: SEQ_Physical_Heater_Shutter: 321줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Physical_Heater_Shutter = 321줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: DX_INF_State_Module <> eModule_Disable: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Disable - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Disable + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Disable THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Disable * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Disable THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: Mode = eShutter_FULL_CLOSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eShutter_FULL_CLOSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eShutter_FULL_CLOSE - 1.0E-6) AND
      Mode <= (eShutter_FULL_CLOSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eShutter_FULL_CLOSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eShutter_FULL_CLOSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eShutter_FULL_CLOSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eShutter_FULL_CLOSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: Mode = eShutter_FULL_OPEN: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eShutter_FULL_OPEN) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eShutter_FULL_OPEN - 1.0E-6) AND
      Mode <= (eShutter_FULL_OPEN + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eShutter_FULL_OPEN THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eShutter_FULL_OPEN * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eShutter_FULL_OPEN THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eShutter_FULL_OPEN) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: Mode = eShutter_CYCLE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eShutter_CYCLE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eShutter_CYCLE - 1.0E-6) AND
      Mode <= (eShutter_CYCLE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eShutter_CYCLE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eShutter_CYCLE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eShutter_CYCLE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eShutter_CYCLE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: DO_Heater_Option_Mode = eHeaterMode_Spike: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DO_Heater_Option_Mode - eHeaterMode_Spike) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DO_Heater_Option_Mode >= (eHeaterMode_Spike - 1.0E-6) AND
      DO_Heater_Option_Mode <= (eHeaterMode_Spike + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DO_Heater_Option_Mode >= eHeaterMode_Spike THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DO_Heater_Option_Mode * 10.0);
   intTarget := REAL_TO_DINT(eHeaterMode_Spike * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DO_Heater_Option_Mode = eHeaterMode_Spike THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DO_Heater_Option_Mode - eHeaterMode_Spike) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: DI_BOAT_ELEVATOR_HOME_POSITION = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_BOAT_ELEVATOR_HOME_POSITION - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_BOAT_ELEVATOR_HOME_POSITION >= (FALSE - 1.0E-6) AND
      DI_BOAT_ELEVATOR_HOME_POSITION <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_BOAT_ELEVATOR_HOME_POSITION >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_BOAT_ELEVATOR_HOME_POSITION * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_BOAT_ELEVATOR_HOME_POSITION = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_BOAT_ELEVATOR_HOME_POSITION - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: DX_INF_State_Boat <> eState_Boat_Home: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Boat - eState_Boat_Home) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Boat >= (eState_Boat_Home - 1.0E-6) AND
      DX_INF_State_Boat <= (eState_Boat_Home + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Boat >= eState_Boat_Home THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Boat * 10.0);
   intTarget := REAL_TO_DINT(eState_Boat_Home * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Boat = eState_Boat_Home THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Boat - eState_Boat_Home) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: DX_Gas_H2_Flow <> eReady_OK: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_Gas_H2_Flow - eReady_OK) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_Gas_H2_Flow >= (eReady_OK - 1.0E-6) AND
      DX_Gas_H2_Flow <= (eReady_OK + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_Gas_H2_Flow >= eReady_OK THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_Gas_H2_Flow * 10.0);
   intTarget := REAL_TO_DINT(eReady_OK * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_Gas_H2_Flow = eReady_OK THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_Gas_H2_Flow - eReady_OK) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: DI_BOAT_ELEVATOR_HOME_POSITION = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_BOAT_ELEVATOR_HOME_POSITION - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_BOAT_ELEVATOR_HOME_POSITION >= (FALSE - 1.0E-6) AND
      DI_BOAT_ELEVATOR_HOME_POSITION <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_BOAT_ELEVATOR_HOME_POSITION >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_BOAT_ELEVATOR_HOME_POSITION * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_BOAT_ELEVATOR_HOME_POSITION = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_BOAT_ELEVATOR_HOME_POSITION - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: DX_INF_State_Boat <> eState_Boat_Home: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Boat - eState_Boat_Home) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Boat >= (eState_Boat_Home - 1.0E-6) AND
      DX_INF_State_Boat <= (eState_Boat_Home + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Boat >= eState_Boat_Home THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Boat * 10.0);
   intTarget := REAL_TO_DINT(eState_Boat_Home * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Boat = eState_Boat_Home THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Boat - eState_Boat_Home) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: DI_HEATER_SHUTTER_CLOSE = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_HEATER_SHUTTER_CLOSE - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_HEATER_SHUTTER_CLOSE >= (FALSE - 1.0E-6) AND
      DI_HEATER_SHUTTER_CLOSE <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_HEATER_SHUTTER_CLOSE >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_HEATER_SHUTTER_CLOSE * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_HEATER_SHUTTER_CLOSE = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_HEATER_SHUTTER_CLOSE - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: DI_HEATER_SHUTTER_OPEN = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_HEATER_SHUTTER_OPEN - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_HEATER_SHUTTER_OPEN >= (TRUE - 1.0E-6) AND
      DI_HEATER_SHUTTER_OPEN <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_HEATER_SHUTTER_OPEN >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_HEATER_SHUTTER_OPEN * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_HEATER_SHUTTER_OPEN = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_HEATER_SHUTTER_OPEN - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: AI_Heater_PV_Spike[iCenter_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iCenter_Zone >= 1 AND
      iCenter_Zone <= 10 THEN
       value := AI_Heater_PV_Spike[iCenter_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iCenter_Zone, 10);
   value := AI_Heater_PV_Spike[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iCenter_Zone >= ARRAY_MIN AND iCenter_Zone <= ARRAY_MAX THEN
       value := AI_Heater_PV_Spike[iCenter_Zone];
   END_IF

예시:

❌ 위험: value := AI_Heater_PV_Spike[iCenter_Zone]; // 범위 검사 없음!

✅ 안전: IF iCenter_Zone >= 1 AND iCenter_Zone <= 10 THEN
value := AI_Heater_PV_Spike[iCenter_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: AI_Heater_PV_Profile[iCenter_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF iCenter_Zone >= 1 AND
      iCenter_Zone <= 10 THEN
       value := AI_Heater_PV_Profile[iCenter_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, iCenter_Zone, 10);
   value := AI_Heater_PV_Profile[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF iCenter_Zone >= ARRAY_MIN AND iCenter_Zone <= ARRAY_MAX THEN
       value := AI_Heater_PV_Profile[iCenter_Zone];
   END_IF

예시:

❌ 위험: value := AI_Heater_PV_Profile[iCenter_Zone]; // 범위 검사 없음!

✅ 안전: IF iCenter_Zone >= 1 AND iCenter_Zone <= 10 THEN
value := AI_Heater_PV_Profile[iCenter_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: Timeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timeout <> NULL THEN
       value := Timeout^;
       // 또는 Timeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timeout) THEN
       value := Timeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timeout := ADR(targetVariable);
   IF Timeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timeout^; // NULL 체크 없음!
value := Timeout.member; // NULL 체크 없음!

✅ 안전: IF Timeout <> NULL THEN
value := Timeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timeout) THEN
value := Timeout.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: eIndex_RSD: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eIndex_RSD <> NULL THEN
       value := eIndex_RSD^;
       // 또는 eIndex_RSD.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eIndex_RSD');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eIndex_RSD) THEN
       value := eIndex_RSD.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eIndex_RSD := ADR(targetVariable);
   IF eIndex_RSD = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eIndex_RSD = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eIndex_RSD^; // NULL 체크 없음!
value := eIndex_RSD.member; // NULL 체크 없음!

✅ 안전: IF eIndex_RSD <> NULL THEN
value := eIndex_RSD^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eIndex_RSD) THEN
value := eIndex_RSD.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: eDesc_Use: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_Use <> NULL THEN
       value := eDesc_Use^;
       // 또는 eDesc_Use.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_Use');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_Use) THEN
       value := eDesc_Use.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_Use := ADR(targetVariable);
   IF eDesc_Use = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_Use = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_Use^; // NULL 체크 없음!
value := eDesc_Use.member; // NULL 체크 없음!

✅ 안전: IF eDesc_Use <> NULL THEN
value := eDesc_Use^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_Use) THEN
value := eDesc_Use.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: eMode_Function_RSD: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eMode_Function_RSD <> NULL THEN
       value := eMode_Function_RSD^;
       // 또는 eMode_Function_RSD.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eMode_Function_RSD');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eMode_Function_RSD) THEN
       value := eMode_Function_RSD.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eMode_Function_RSD := ADR(targetVariable);
   IF eMode_Function_RSD = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eMode_Function_RSD = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eMode_Function_RSD^; // NULL 체크 없음!
value := eMode_Function_RSD.member; // NULL 체크 없음!

✅ 안전: IF eMode_Function_RSD <> NULL THEN
value := eMode_Function_RSD^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eMode_Function_RSD) THEN
value := eMode_Function_RSD.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: SEQ_Physical_RSD: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF SEQ_Physical_RSD <> NULL THEN
       value := SEQ_Physical_RSD^;
       // 또는 SEQ_Physical_RSD.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: SEQ_Physical_RSD');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(SEQ_Physical_RSD) THEN
       value := SEQ_Physical_RSD.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   SEQ_Physical_RSD := ADR(targetVariable);
   IF SEQ_Physical_RSD = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF SEQ_Physical_RSD = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := SEQ_Physical_RSD^; // NULL 체크 없음!
value := SEQ_Physical_RSD.member; // NULL 체크 없음!

✅ 안전: IF SEQ_Physical_RSD <> NULL THEN
value := SEQ_Physical_RSD^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(SEQ_Physical_RSD) THEN
value := SEQ_Physical_RSD.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: eMode_Function_RSD: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eMode_Function_RSD <> NULL THEN
       value := eMode_Function_RSD^;
       // 또는 eMode_Function_RSD.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eMode_Function_RSD');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eMode_Function_RSD) THEN
       value := eMode_Function_RSD.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eMode_Function_RSD := ADR(targetVariable);
   IF eMode_Function_RSD = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eMode_Function_RSD = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eMode_Function_RSD^; // NULL 체크 없음!
value := eMode_Function_RSD.member; // NULL 체크 없음!

✅ 안전: IF eMode_Function_RSD <> NULL THEN
value := eMode_Function_RSD^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eMode_Function_RSD) THEN
value := eMode_Function_RSD.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: SEQ_Physical_RSD: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF SEQ_Physical_RSD <> NULL THEN
       value := SEQ_Physical_RSD^;
       // 또는 SEQ_Physical_RSD.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: SEQ_Physical_RSD');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(SEQ_Physical_RSD) THEN
       value := SEQ_Physical_RSD.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   SEQ_Physical_RSD := ADR(targetVariable);
   IF SEQ_Physical_RSD = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF SEQ_Physical_RSD = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := SEQ_Physical_RSD^; // NULL 체크 없음!
value := SEQ_Physical_RSD.member; // NULL 체크 없음!

✅ 안전: IF SEQ_Physical_RSD <> NULL THEN
value := SEQ_Physical_RSD^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(SEQ_Physical_RSD) THEN
value := SEQ_Physical_RSD.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: SEQ_Physical_RSD: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF SEQ_Physical_RSD <> NULL THEN
       value := SEQ_Physical_RSD^;
       // 또는 SEQ_Physical_RSD.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: SEQ_Physical_RSD');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(SEQ_Physical_RSD) THEN
       value := SEQ_Physical_RSD.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   SEQ_Physical_RSD := ADR(targetVariable);
   IF SEQ_Physical_RSD = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF SEQ_Physical_RSD = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := SEQ_Physical_RSD^; // NULL 체크 없음!
value := SEQ_Physical_RSD.member; // NULL 체크 없음!

✅ 안전: IF SEQ_Physical_RSD <> NULL THEN
value := SEQ_Physical_RSD^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(SEQ_Physical_RSD) THEN
value := SEQ_Physical_RSD.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: SEQ_Physical_RSD: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF SEQ_Physical_RSD <> NULL THEN
       value := SEQ_Physical_RSD^;
       // 또는 SEQ_Physical_RSD.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: SEQ_Physical_RSD');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(SEQ_Physical_RSD) THEN
       value := SEQ_Physical_RSD.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   SEQ_Physical_RSD := ADR(targetVariable);
   IF SEQ_Physical_RSD = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF SEQ_Physical_RSD = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := SEQ_Physical_RSD^; // NULL 체크 없음!
value := SEQ_Physical_RSD.member; // NULL 체크 없음!

✅ 안전: IF SEQ_Physical_RSD <> NULL THEN
value := SEQ_Physical_RSD^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(SEQ_Physical_RSD) THEN
value := SEQ_Physical_RSD.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: eIndex_RSD: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eIndex_RSD <> NULL THEN
       value := eIndex_RSD^;
       // 또는 eIndex_RSD.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eIndex_RSD');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eIndex_RSD) THEN
       value := eIndex_RSD.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eIndex_RSD := ADR(targetVariable);
   IF eIndex_RSD = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eIndex_RSD = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eIndex_RSD^; // NULL 체크 없음!
value := eIndex_RSD.member; // NULL 체크 없음!

✅ 안전: IF eIndex_RSD <> NULL THEN
value := eIndex_RSD^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eIndex_RSD) THEN
value := eIndex_RSD.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: eMode_Function_RSD: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eMode_Function_RSD <> NULL THEN
       value := eMode_Function_RSD^;
       // 또는 eMode_Function_RSD.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eMode_Function_RSD');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eMode_Function_RSD) THEN
       value := eMode_Function_RSD.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eMode_Function_RSD := ADR(targetVariable);
   IF eMode_Function_RSD = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eMode_Function_RSD = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eMode_Function_RSD^; // NULL 체크 없음!
value := eMode_Function_RSD.member; // NULL 체크 없음!

✅ 안전: IF eMode_Function_RSD <> NULL THEN
value := eMode_Function_RSD^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eMode_Function_RSD) THEN
value := eMode_Function_RSD.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: SEQ_Physical_LoadLock: 2402줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Physical_LoadLock = 2402줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: DX_INF_State_Module <> eModule_Disable: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Disable - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Disable + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Disable THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Disable * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Disable THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: Mode = eMode_LoadLock_MNT: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_LoadLock_MNT) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_LoadLock_MNT - 1.0E-6) AND
      Mode <= (eMode_LoadLock_MNT + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_LoadLock_MNT THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_LoadLock_MNT * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_LoadLock_MNT THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_LoadLock_MNT) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: Mode = eMode_LoadLock: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_LoadLock) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_LoadLock - 1.0E-6) AND
      Mode <= (eMode_LoadLock + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_LoadLock THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_LoadLock * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_LoadLock THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_LoadLock) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: Mode = eMode_LoadLock: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_LoadLock) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_LoadLock - 1.0E-6) AND
      Mode <= (eMode_LoadLock + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_LoadLock THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_LoadLock * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_LoadLock THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_LoadLock) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: Mode = eMode_ATM: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_ATM) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_ATM - 1.0E-6) AND
      Mode <= (eMode_ATM + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_ATM THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_ATM * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_ATM THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_ATM) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: Mode = eMode_Pass: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_Pass) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_Pass - 1.0E-6) AND
      Mode <= (eMode_Pass + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_Pass THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_Pass * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_Pass THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_Pass) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: Mode = eMode_ATM_MNT: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_ATM_MNT) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_ATM_MNT - 1.0E-6) AND
      Mode <= (eMode_ATM_MNT + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_ATM_MNT THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_ATM_MNT * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_ATM_MNT THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_ATM_MNT) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: Mode = eMode_LoadLock_MNT: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_LoadLock_MNT) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_LoadLock_MNT - 1.0E-6) AND
      Mode <= (eMode_LoadLock_MNT + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_LoadLock_MNT THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_LoadLock_MNT * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_LoadLock_MNT THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_LoadLock_MNT) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: Mode = eMode_Pass_MNT: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_Pass_MNT) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_Pass_MNT - 1.0E-6) AND
      Mode <= (eMode_Pass_MNT + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_Pass_MNT THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_Pass_MNT * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_Pass_MNT THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_Pass_MNT) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: DI_AV81_OPEN = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_AV81_OPEN - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_AV81_OPEN >= (FALSE - 1.0E-6) AND
      DI_AV81_OPEN <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_AV81_OPEN >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_AV81_OPEN * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_AV81_OPEN = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_AV81_OPEN - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: DI_AV82_OPEN = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_AV82_OPEN - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_AV82_OPEN >= (FALSE - 1.0E-6) AND
      DI_AV82_OPEN <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_AV82_OPEN >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_AV82_OPEN * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_AV82_OPEN = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_AV82_OPEN - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: Q = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (FALSE - 1.0E-6) AND
      Q <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: DI_AV81_OPEN = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_AV81_OPEN - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_AV81_OPEN >= (TRUE - 1.0E-6) AND
      DI_AV81_OPEN <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_AV81_OPEN >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_AV81_OPEN * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_AV81_OPEN = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_AV81_OPEN - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: DI_AV82_OPEN = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_AV82_OPEN - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_AV82_OPEN >= (TRUE - 1.0E-6) AND
      DI_AV82_OPEN <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_AV82_OPEN >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_AV82_OPEN * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_AV82_OPEN = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_AV82_OPEN - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: DX_Loadlock_RSD_TOP_Action = eRSD_UNKNOWN: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_Loadlock_RSD_TOP_Action - eRSD_UNKNOWN) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_Loadlock_RSD_TOP_Action >= (eRSD_UNKNOWN - 1.0E-6) AND
      DX_Loadlock_RSD_TOP_Action <= (eRSD_UNKNOWN + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_Loadlock_RSD_TOP_Action >= eRSD_UNKNOWN THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_Loadlock_RSD_TOP_Action * 10.0);
   intTarget := REAL_TO_DINT(eRSD_UNKNOWN * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_Loadlock_RSD_TOP_Action = eRSD_UNKNOWN THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_Loadlock_RSD_TOP_Action - eRSD_UNKNOWN) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: DX_Loadlock_RSD_TOP_Action = DI_RSD_Damper_Mode: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_Loadlock_RSD_TOP_Action - DI_RSD_Damper_Mode) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_Loadlock_RSD_TOP_Action >= (DI_RSD_Damper_Mode - 1.0E-6) AND
      DX_Loadlock_RSD_TOP_Action <= (DI_RSD_Damper_Mode + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_Loadlock_RSD_TOP_Action >= DI_RSD_Damper_Mode THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_Loadlock_RSD_TOP_Action * 10.0);
   intTarget := REAL_TO_DINT(DI_RSD_Damper_Mode * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_Loadlock_RSD_TOP_Action = DI_RSD_Damper_Mode THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_Loadlock_RSD_TOP_Action - DI_RSD_Damper_Mode) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: AO_MFC_SET[cMFC81_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC81_Index >= 1 AND
      cMFC81_Index <= 10 THEN
       value := AO_MFC_SET[cMFC81_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC81_Index, 10);
   value := AO_MFC_SET[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC81_Index >= ARRAY_MIN AND cMFC81_Index <= ARRAY_MAX THEN
       value := AO_MFC_SET[cMFC81_Index];
   END_IF

예시:

❌ 위험: value := AO_MFC_SET[cMFC81_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC81_Index >= 1 AND cMFC81_Index <= 10 THEN
value := AO_MFC_SET[cMFC81_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: AO_MFC_SET[cMFC82_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC82_Index >= 1 AND
      cMFC82_Index <= 10 THEN
       value := AO_MFC_SET[cMFC82_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC82_Index, 10);
   value := AO_MFC_SET[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC82_Index >= ARRAY_MIN AND cMFC82_Index <= ARRAY_MAX THEN
       value := AO_MFC_SET[cMFC82_Index];
   END_IF

예시:

❌ 위험: value := AO_MFC_SET[cMFC82_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC82_Index >= 1 AND cMFC82_Index <= 10 THEN
value := AO_MFC_SET[cMFC82_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: DX_MFC_Mode[cMFC81_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC81_Index >= 1 AND
      cMFC81_Index <= 10 THEN
       value := DX_MFC_Mode[cMFC81_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC81_Index, 10);
   value := DX_MFC_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC81_Index >= ARRAY_MIN AND cMFC81_Index <= ARRAY_MAX THEN
       value := DX_MFC_Mode[cMFC81_Index];
   END_IF

예시:

❌ 위험: value := DX_MFC_Mode[cMFC81_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC81_Index >= 1 AND cMFC81_Index <= 10 THEN
value := DX_MFC_Mode[cMFC81_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: DX_MFC_Mode[cMFC82_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC82_Index >= 1 AND
      cMFC82_Index <= 10 THEN
       value := DX_MFC_Mode[cMFC82_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC82_Index, 10);
   value := DX_MFC_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC82_Index >= ARRAY_MIN AND cMFC82_Index <= ARRAY_MAX THEN
       value := DX_MFC_Mode[cMFC82_Index];
   END_IF

예시:

❌ 위험: value := DX_MFC_Mode[cMFC82_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC82_Index >= 1 AND cMFC82_Index <= 10 THEN
value := DX_MFC_Mode[cMFC82_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: DX_CFG_RSD_Use[eIndex_RSD.eLDA_EXH]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF eIndex_RSD.eLDA_EXH >= 1 AND
      eIndex_RSD.eLDA_EXH <= 10 THEN
       value := DX_CFG_RSD_Use[eIndex_RSD.eLDA_EXH];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, eIndex_RSD.eLDA_EXH, 10);
   value := DX_CFG_RSD_Use[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF eIndex_RSD.eLDA_EXH >= ARRAY_MIN AND eIndex_RSD.eLDA_EXH <= ARRAY_MAX THEN
       value := DX_CFG_RSD_Use[eIndex_RSD.eLDA_EXH];
   END_IF

예시:

❌ 위험: value := DX_CFG_RSD_Use[eIndex_RSD.eLDA_EXH]; // 범위 검사 없음!

✅ 안전: IF eIndex_RSD.eLDA_EXH >= 1 AND eIndex_RSD.eLDA_EXH <= 10 THEN
value := DX_CFG_RSD_Use[eIndex_RSD.eLDA_EXH];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: DI_RSD_Damper_Mode[eIndex_RSD.eLDA_EXH]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF eIndex_RSD.eLDA_EXH >= 1 AND
      eIndex_RSD.eLDA_EXH <= 10 THEN
       value := DI_RSD_Damper_Mode[eIndex_RSD.eLDA_EXH];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, eIndex_RSD.eLDA_EXH, 10);
   value := DI_RSD_Damper_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF eIndex_RSD.eLDA_EXH >= ARRAY_MIN AND eIndex_RSD.eLDA_EXH <= ARRAY_MAX THEN
       value := DI_RSD_Damper_Mode[eIndex_RSD.eLDA_EXH];
   END_IF

예시:

❌ 위험: value := DI_RSD_Damper_Mode[eIndex_RSD.eLDA_EXH]; // 범위 검사 없음!

✅ 안전: IF eIndex_RSD.eLDA_EXH >= 1 AND eIndex_RSD.eLDA_EXH <= 10 THEN
value := DI_RSD_Damper_Mode[eIndex_RSD.eLDA_EXH];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: Timeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timeout <> NULL THEN
       value := Timeout^;
       // 또는 Timeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timeout) THEN
       value := Timeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timeout := ADR(targetVariable);
   IF Timeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timeout^; // NULL 체크 없음!
value := Timeout.member; // NULL 체크 없음!

✅ 안전: IF Timeout <> NULL THEN
value := Timeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timeout) THEN
value := Timeout.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: Pressure_Check: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Pressure_Check <> NULL THEN
       value := Pressure_Check^;
       // 또는 Pressure_Check.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Pressure_Check');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Pressure_Check) THEN
       value := Pressure_Check.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Pressure_Check := ADR(targetVariable);
   IF Pressure_Check = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Pressure_Check = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Pressure_Check^; // NULL 체크 없음!
value := Pressure_Check.member; // NULL 체크 없음!

✅ 안전: IF Pressure_Check <> NULL THEN
value := Pressure_Check^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Pressure_Check) THEN
value := Pressure_Check.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: Timeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timeout <> NULL THEN
       value := Timeout^;
       // 또는 Timeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timeout) THEN
       value := Timeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timeout := ADR(targetVariable);
   IF Timeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timeout^; // NULL 체크 없음!
value := Timeout.member; // NULL 체크 없음!

✅ 안전: IF Timeout <> NULL THEN
value := Timeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timeout) THEN
value := Timeout.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: SEQ_Physical_LPV: 242줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Physical_LPV = 242줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: DX_INF_State_Module <> eModule_Disable: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Disable - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Disable + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Disable THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Disable * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Disable THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: Mode = eTVLPV_CLOSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eTVLPV_CLOSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eTVLPV_CLOSE - 1.0E-6) AND
      Mode <= (eTVLPV_CLOSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eTVLPV_CLOSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eTVLPV_CLOSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eTVLPV_CLOSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eTVLPV_CLOSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: Mode = eTVLPV_OPEN: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eTVLPV_OPEN) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eTVLPV_OPEN - 1.0E-6) AND
      Mode <= (eTVLPV_OPEN + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eTVLPV_OPEN THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eTVLPV_OPEN * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eTVLPV_OPEN THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eTVLPV_OPEN) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: Mode = eTVLPV_PRESSURE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eTVLPV_PRESSURE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eTVLPV_PRESSURE - 1.0E-6) AND
      Mode <= (eTVLPV_PRESSURE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eTVLPV_PRESSURE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eTVLPV_PRESSURE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eTVLPV_PRESSURE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eTVLPV_PRESSURE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: Mode = eTVLPV_POSITION: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eTVLPV_POSITION) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eTVLPV_POSITION - 1.0E-6) AND
      Mode <= (eTVLPV_POSITION + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eTVLPV_POSITION THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eTVLPV_POSITION * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eTVLPV_POSITION THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eTVLPV_POSITION) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: DI_LPV_Valve_Status = eTVLPV_CLOSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_LPV_Valve_Status - eTVLPV_CLOSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_LPV_Valve_Status >= (eTVLPV_CLOSE - 1.0E-6) AND
      DI_LPV_Valve_Status <= (eTVLPV_CLOSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_LPV_Valve_Status >= eTVLPV_CLOSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_LPV_Valve_Status * 10.0);
   intTarget := REAL_TO_DINT(eTVLPV_CLOSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_LPV_Valve_Status = eTVLPV_CLOSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_LPV_Valve_Status - eTVLPV_CLOSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: Ctrl = eIdle: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eIdle) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eIdle - 1.0E-6) AND
      Ctrl <= (eIdle + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eIdle THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eIdle * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eIdle THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eIdle) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: DI_LPV_Valve_Status = eTVLPV_PRESSURE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_LPV_Valve_Status - eTVLPV_PRESSURE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_LPV_Valve_Status >= (eTVLPV_PRESSURE - 1.0E-6) AND
      DI_LPV_Valve_Status <= (eTVLPV_PRESSURE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_LPV_Valve_Status >= eTVLPV_PRESSURE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_LPV_Valve_Status * 10.0);
   intTarget := REAL_TO_DINT(eTVLPV_PRESSURE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_LPV_Valve_Status = eTVLPV_PRESSURE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_LPV_Valve_Status - eTVLPV_PRESSURE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: DI_LPV_Valve_Status = eTVLPV_OPEN: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_LPV_Valve_Status - eTVLPV_OPEN) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_LPV_Valve_Status >= (eTVLPV_OPEN - 1.0E-6) AND
      DI_LPV_Valve_Status <= (eTVLPV_OPEN + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_LPV_Valve_Status >= eTVLPV_OPEN THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_LPV_Valve_Status * 10.0);
   intTarget := REAL_TO_DINT(eTVLPV_OPEN * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_LPV_Valve_Status = eTVLPV_OPEN THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_LPV_Valve_Status - eTVLPV_OPEN) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: eIndex_RSD: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eIndex_RSD <> NULL THEN
       value := eIndex_RSD^;
       // 또는 eIndex_RSD.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eIndex_RSD');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eIndex_RSD) THEN
       value := eIndex_RSD.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eIndex_RSD := ADR(targetVariable);
   IF eIndex_RSD = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eIndex_RSD = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eIndex_RSD^; // NULL 체크 없음!
value := eIndex_RSD.member; // NULL 체크 없음!

✅ 안전: IF eIndex_RSD <> NULL THEN
value := eIndex_RSD^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eIndex_RSD) THEN
value := eIndex_RSD.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: SEQ_Physical_RSD: 391줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Physical_RSD = 391줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: DX_INF_State_Module <> eModule_Disable: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Disable - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Disable + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Disable THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Disable * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Disable THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: DX_INF_State_Process = eProcess_Processing: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Process >= (eProcess_Processing - 1.0E-6) AND
      DX_INF_State_Process <= (eProcess_Processing + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Process >= eProcess_Processing THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Process * 10.0);
   intTarget := REAL_TO_DINT(eProcess_Processing * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Process = eProcess_Processing THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: i = eIndex_RSD.eLDA_EXH: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(i - eIndex_RSD.eLDA_EXH) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF i >= (eIndex_RSD.eLDA_EXH - 1.0E-6) AND
      i <= (eIndex_RSD.eLDA_EXH + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF i >= eIndex_RSD.eLDA_EXH THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(i * 10.0);
   intTarget := REAL_TO_DINT(eIndex_RSD.eLDA_EXH * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF i = eIndex_RSD.eLDA_EXH THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(i - eIndex_RSD.eLDA_EXH) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ARRAY[0..47]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 0..47 >= 1 AND
      0..47 <= 10 THEN
       value := ARRAY[0..47];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 0..47, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 0..47 >= ARRAY_MIN AND 0..47 <= ARRAY_MAX THEN
       value := ARRAY[0..47];
   END_IF

예시:

❌ 위험: value := ARRAY[0..47]; // 범위 검사 없음!

✅ 안전: IF 0..47 >= 1 AND 0..47 <= 10 THEN
value := ARRAY[0..47];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ARRAY[1..cMAX_RSD_Damper]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_RSD_Damper >= 1 AND
      1..cMAX_RSD_Damper <= 10 THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_RSD_Damper, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_RSD_Damper >= ARRAY_MIN AND 1..cMAX_RSD_Damper <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_RSD_Damper]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_RSD_Damper >= 1 AND 1..cMAX_RSD_Damper <= 10 THEN
value := ARRAY[1..cMAX_RSD_Damper];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ARRAY[1..cMAX_RSD_Damper]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_RSD_Damper >= 1 AND
      1..cMAX_RSD_Damper <= 10 THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_RSD_Damper, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_RSD_Damper >= ARRAY_MIN AND 1..cMAX_RSD_Damper <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_RSD_Damper]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_RSD_Damper >= 1 AND 1..cMAX_RSD_Damper <= 10 THEN
value := ARRAY[1..cMAX_RSD_Damper];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ARRAY[1..cMAX_RSD_Damper]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_RSD_Damper >= 1 AND
      1..cMAX_RSD_Damper <= 10 THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_RSD_Damper, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_RSD_Damper >= ARRAY_MIN AND 1..cMAX_RSD_Damper <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_RSD_Damper]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_RSD_Damper >= 1 AND 1..cMAX_RSD_Damper <= 10 THEN
value := ARRAY[1..cMAX_RSD_Damper];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ARRAY[1..cMAX_RSD_Damper]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_RSD_Damper >= 1 AND
      1..cMAX_RSD_Damper <= 10 THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_RSD_Damper, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_RSD_Damper >= ARRAY_MIN AND 1..cMAX_RSD_Damper <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_RSD_Damper]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_RSD_Damper >= 1 AND 1..cMAX_RSD_Damper <= 10 THEN
value := ARRAY[1..cMAX_RSD_Damper];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ARRAY[1..cMAX_RSD_Damper]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_RSD_Damper >= 1 AND
      1..cMAX_RSD_Damper <= 10 THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_RSD_Damper, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_RSD_Damper >= ARRAY_MIN AND 1..cMAX_RSD_Damper <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_RSD_Damper]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_RSD_Damper >= 1 AND 1..cMAX_RSD_Damper <= 10 THEN
value := ARRAY[1..cMAX_RSD_Damper];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ARRAY[1..cMAX_RSD_Damper]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_RSD_Damper >= 1 AND
      1..cMAX_RSD_Damper <= 10 THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_RSD_Damper, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_RSD_Damper >= ARRAY_MIN AND 1..cMAX_RSD_Damper <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_RSD_Damper]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_RSD_Damper >= 1 AND 1..cMAX_RSD_Damper <= 10 THEN
value := ARRAY[1..cMAX_RSD_Damper];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ARRAY[1..cMAX_RSD_Damper]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_RSD_Damper >= 1 AND
      1..cMAX_RSD_Damper <= 10 THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_RSD_Damper, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_RSD_Damper >= ARRAY_MIN AND 1..cMAX_RSD_Damper <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_RSD_Damper]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_RSD_Damper >= 1 AND 1..cMAX_RSD_Damper <= 10 THEN
value := ARRAY[1..cMAX_RSD_Damper];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ARRAY[1..cMAX_RSD_Damper]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_RSD_Damper >= 1 AND
      1..cMAX_RSD_Damper <= 10 THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_RSD_Damper, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_RSD_Damper >= ARRAY_MIN AND 1..cMAX_RSD_Damper <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_RSD_Damper]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_RSD_Damper >= 1 AND 1..cMAX_RSD_Damper <= 10 THEN
value := ARRAY[1..cMAX_RSD_Damper];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ARRAY[1..cMAX_RSD_Damper]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_RSD_Damper >= 1 AND
      1..cMAX_RSD_Damper <= 10 THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_RSD_Damper, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_RSD_Damper >= ARRAY_MIN AND 1..cMAX_RSD_Damper <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_RSD_Damper]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_RSD_Damper >= 1 AND 1..cMAX_RSD_Damper <= 10 THEN
value := ARRAY[1..cMAX_RSD_Damper];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ARRAY[1..cMAX_RSD_Damper]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_RSD_Damper >= 1 AND
      1..cMAX_RSD_Damper <= 10 THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_RSD_Damper, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_RSD_Damper >= ARRAY_MIN AND 1..cMAX_RSD_Damper <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_RSD_Damper];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_RSD_Damper]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_RSD_Damper >= 1 AND 1..cMAX_RSD_Damper <= 10 THEN
value := ARRAY[1..cMAX_RSD_Damper];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: DX_CFG_RSD_Use[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DX_CFG_RSD_Use[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DX_CFG_RSD_Use[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DX_CFG_RSD_Use[i];
   END_IF

예시:

❌ 위험: value := DX_CFG_RSD_Use[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DX_CFG_RSD_Use[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: DX_CFG_RSD_Use[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DX_CFG_RSD_Use[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DX_CFG_RSD_Use[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DX_CFG_RSD_Use[i];
   END_IF

예시:

❌ 위험: value := DX_CFG_RSD_Use[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DX_CFG_RSD_Use[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: DO_RSD_Mode[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DO_RSD_Mode[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DO_RSD_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DO_RSD_Mode[i];
   END_IF

예시:

❌ 위험: value := DO_RSD_Mode[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DO_RSD_Mode[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: PID_Start[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := PID_Start[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := PID_Start[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := PID_Start[i];
   END_IF

예시:

❌ 위험: value := PID_Start[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := PID_Start[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: DO_RSD_Mode[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DO_RSD_Mode[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DO_RSD_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DO_RSD_Mode[i];
   END_IF

예시:

❌ 위험: value := DO_RSD_Mode[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DO_RSD_Mode[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ioAO_ECAT_RSD_Set[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAO_ECAT_RSD_Set[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAO_ECAT_RSD_Set[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAO_ECAT_RSD_Set[i];
   END_IF

예시:

❌ 위험: value := ioAO_ECAT_RSD_Set[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAO_ECAT_RSD_Set[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ioAO_ECAT_RSD_Set[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAO_ECAT_RSD_Set[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAO_ECAT_RSD_Set[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAO_ECAT_RSD_Set[i];
   END_IF

예시:

❌ 위험: value := ioAO_ECAT_RSD_Set[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAO_ECAT_RSD_Set[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ioAO_ECAT_RSD_Set[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAO_ECAT_RSD_Set[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAO_ECAT_RSD_Set[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAO_ECAT_RSD_Set[i];
   END_IF

예시:

❌ 위험: value := ioAO_ECAT_RSD_Set[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAO_ECAT_RSD_Set[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ioAO_ECAT_RSD_Set[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAO_ECAT_RSD_Set[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAO_ECAT_RSD_Set[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAO_ECAT_RSD_Set[i];
   END_IF

예시:

❌ 위험: value := ioAO_ECAT_RSD_Set[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAO_ECAT_RSD_Set[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: DO_RSD_Mode[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DO_RSD_Mode[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DO_RSD_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DO_RSD_Mode[i];
   END_IF

예시:

❌ 위험: value := DO_RSD_Mode[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DO_RSD_Mode[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ioAO_ECAT_RSD_Set[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAO_ECAT_RSD_Set[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAO_ECAT_RSD_Set[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAO_ECAT_RSD_Set[i];
   END_IF

예시:

❌ 위험: value := ioAO_ECAT_RSD_Set[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAO_ECAT_RSD_Set[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ioAO_ECAT_RSD_Set[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAO_ECAT_RSD_Set[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAO_ECAT_RSD_Set[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAO_ECAT_RSD_Set[i];
   END_IF

예시:

❌ 위험: value := ioAO_ECAT_RSD_Set[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAO_ECAT_RSD_Set[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ioAO_ECAT_RSD_Set[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAO_ECAT_RSD_Set[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAO_ECAT_RSD_Set[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAO_ECAT_RSD_Set[i];
   END_IF

예시:

❌ 위험: value := ioAO_ECAT_RSD_Set[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAO_ECAT_RSD_Set[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ioAO_ECAT_RSD_Set[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAO_ECAT_RSD_Set[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAO_ECAT_RSD_Set[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAO_ECAT_RSD_Set[i];
   END_IF

예시:

❌ 위험: value := ioAO_ECAT_RSD_Set[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAO_ECAT_RSD_Set[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: DO_RSD_Mode[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DO_RSD_Mode[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DO_RSD_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DO_RSD_Mode[i];
   END_IF

예시:

❌ 위험: value := DO_RSD_Mode[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DO_RSD_Mode[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: OUT_RSD_Damper_Position[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := OUT_RSD_Damper_Position[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := OUT_RSD_Damper_Position[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := OUT_RSD_Damper_Position[i];
   END_IF

예시:

❌ 위험: value := OUT_RSD_Damper_Position[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := OUT_RSD_Damper_Position[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: AO_RSD_Position[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := AO_RSD_Position[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := AO_RSD_Position[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := AO_RSD_Position[i];
   END_IF

예시:

❌ 위험: value := AO_RSD_Position[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := AO_RSD_Position[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ioAO_ECAT_RSD_Set[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAO_ECAT_RSD_Set[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAO_ECAT_RSD_Set[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAO_ECAT_RSD_Set[i];
   END_IF

예시:

❌ 위험: value := ioAO_ECAT_RSD_Set[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAO_ECAT_RSD_Set[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ioAO_ECAT_RSD_Set[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAO_ECAT_RSD_Set[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAO_ECAT_RSD_Set[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAO_ECAT_RSD_Set[i];
   END_IF

예시:

❌ 위험: value := ioAO_ECAT_RSD_Set[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAO_ECAT_RSD_Set[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ioAO_ECAT_RSD_Set[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAO_ECAT_RSD_Set[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAO_ECAT_RSD_Set[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAO_ECAT_RSD_Set[i];
   END_IF

예시:

❌ 위험: value := ioAO_ECAT_RSD_Set[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAO_ECAT_RSD_Set[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: ioAO_ECAT_RSD_Set[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioAO_ECAT_RSD_Set[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioAO_ECAT_RSD_Set[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioAO_ECAT_RSD_Set[i];
   END_IF

예시:

❌ 위험: value := ioAO_ECAT_RSD_Set[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioAO_ECAT_RSD_Set[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: DO_RSD_Mode[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DO_RSD_Mode[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DO_RSD_Mode[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DO_RSD_Mode[i];
   END_IF

예시:

❌ 위험: value := DO_RSD_Mode[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DO_RSD_Mode[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: fbBPID[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := fbBPID[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := fbBPID[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := fbBPID[i];
   END_IF

예시:

❌ 위험: value := fbBPID[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := fbBPID[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: fbBPID[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := fbBPID[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := fbBPID[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := fbBPID[i];
   END_IF

예시:

❌ 위험: value := fbBPID[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := fbBPID[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: PID_RSD_Damper_Pressure[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := PID_RSD_Damper_Pressure[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := PID_RSD_Damper_Pressure[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := PID_RSD_Damper_Pressure[i];
   END_IF

예시:

❌ 위험: value := PID_RSD_Damper_Pressure[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := PID_RSD_Damper_Pressure[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: AO_RSD_Pressure[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := AO_RSD_Pressure[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := AO_RSD_Pressure[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := AO_RSD_Pressure[i];
   END_IF

예시:

❌ 위험: value := AO_RSD_Pressure[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := AO_RSD_Pressure[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: PID_Start[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := PID_Start[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := PID_Start[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := PID_Start[i];
   END_IF

예시:

❌ 위험: value := PID_Start[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := PID_Start[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: PID_Delay[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := PID_Delay[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := PID_Delay[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := PID_Delay[i];
   END_IF

예시:

❌ 위험: value := PID_Delay[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := PID_Delay[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: PID_Rel_Check_Delay[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := PID_Rel_Check_Delay[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := PID_Rel_Check_Delay[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := PID_Rel_Check_Delay[i];
   END_IF

예시:

❌ 위험: value := PID_Rel_Check_Delay[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := PID_Rel_Check_Delay[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: simul_Sleep: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF simul_Sleep <> NULL THEN
       value := simul_Sleep^;
       // 또는 simul_Sleep.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: simul_Sleep');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(simul_Sleep) THEN
       value := simul_Sleep.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   simul_Sleep := ADR(targetVariable);
   IF simul_Sleep = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF simul_Sleep = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := simul_Sleep^; // NULL 체크 없음!
value := simul_Sleep.member; // NULL 체크 없음!

✅ 안전: IF simul_Sleep <> NULL THEN
value := simul_Sleep^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(simul_Sleep) THEN
value := simul_Sleep.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: SEQ_Physical_TV_VAT: 400줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Physical_TV_VAT = 400줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: old_Mode <> Mode: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(old_Mode - Mode) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF old_Mode >= (Mode - 1.0E-6) AND
      old_Mode <= (Mode + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF old_Mode >= Mode THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(old_Mode * 10.0);
   intTarget := REAL_TO_DINT(Mode * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF old_Mode = Mode THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(old_Mode - Mode) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: Mode = eTV_VAT_CLOSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eTV_VAT_CLOSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eTV_VAT_CLOSE - 1.0E-6) AND
      Mode <= (eTV_VAT_CLOSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eTV_VAT_CLOSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eTV_VAT_CLOSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eTV_VAT_CLOSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eTV_VAT_CLOSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: Mode = eTV_VAT_OPEN: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eTV_VAT_OPEN) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eTV_VAT_OPEN - 1.0E-6) AND
      Mode <= (eTV_VAT_OPEN + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eTV_VAT_OPEN THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eTV_VAT_OPEN * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eTV_VAT_OPEN THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eTV_VAT_OPEN) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: Mode = eTV_VAT_POSITION: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eTV_VAT_POSITION) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eTV_VAT_POSITION - 1.0E-6) AND
      Mode <= (eTV_VAT_POSITION + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eTV_VAT_POSITION THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eTV_VAT_POSITION * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eTV_VAT_POSITION THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eTV_VAT_POSITION) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: Mode = eTV_VAT_PRESSURE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eTV_VAT_PRESSURE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eTV_VAT_PRESSURE - 1.0E-6) AND
      Mode <= (eTV_VAT_PRESSURE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eTV_VAT_PRESSURE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eTV_VAT_PRESSURE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eTV_VAT_PRESSURE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eTV_VAT_PRESSURE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: Ctrl <> eAborted: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAborted) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAborted - 1.0E-6) AND
      Ctrl <= (eAborted + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAborted THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAborted * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAborted THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAborted) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: DI_TV_VAT_Mode <> edTV_VAT_Close: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_TV_VAT_Mode - edTV_VAT_Close) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_TV_VAT_Mode >= (edTV_VAT_Close - 1.0E-6) AND
      DI_TV_VAT_Mode <= (edTV_VAT_Close + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_TV_VAT_Mode >= edTV_VAT_Close THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_TV_VAT_Mode * 10.0);
   intTarget := REAL_TO_DINT(edTV_VAT_Close * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_TV_VAT_Mode = edTV_VAT_Close THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_TV_VAT_Mode - edTV_VAT_Close) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: DI_TV_VAT_Mode = edTV_VAT_Close: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_TV_VAT_Mode - edTV_VAT_Close) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_TV_VAT_Mode >= (edTV_VAT_Close - 1.0E-6) AND
      DI_TV_VAT_Mode <= (edTV_VAT_Close + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_TV_VAT_Mode >= edTV_VAT_Close THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_TV_VAT_Mode * 10.0);
   intTarget := REAL_TO_DINT(edTV_VAT_Close * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_TV_VAT_Mode = edTV_VAT_Close THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_TV_VAT_Mode - edTV_VAT_Close) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: DO_TV_VAT_Mode = edTV_VAT_Close: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DO_TV_VAT_Mode - edTV_VAT_Close) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DO_TV_VAT_Mode >= (edTV_VAT_Close - 1.0E-6) AND
      DO_TV_VAT_Mode <= (edTV_VAT_Close + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DO_TV_VAT_Mode >= edTV_VAT_Close THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DO_TV_VAT_Mode * 10.0);
   intTarget := REAL_TO_DINT(edTV_VAT_Close * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DO_TV_VAT_Mode = edTV_VAT_Close THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DO_TV_VAT_Mode - edTV_VAT_Close) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: DI_TV_VAT_Mode = edTV_VAT_Close: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_TV_VAT_Mode - edTV_VAT_Close) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_TV_VAT_Mode >= (edTV_VAT_Close - 1.0E-6) AND
      DI_TV_VAT_Mode <= (edTV_VAT_Close + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_TV_VAT_Mode >= edTV_VAT_Close THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_TV_VAT_Mode * 10.0);
   intTarget := REAL_TO_DINT(edTV_VAT_Close * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_TV_VAT_Mode = edTV_VAT_Close THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_TV_VAT_Mode - edTV_VAT_Close) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: DI_BOAT_ELEVATOR_CAP_CLOSE = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_BOAT_ELEVATOR_CAP_CLOSE - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_BOAT_ELEVATOR_CAP_CLOSE >= (FALSE - 1.0E-6) AND
      DI_BOAT_ELEVATOR_CAP_CLOSE <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_BOAT_ELEVATOR_CAP_CLOSE >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_BOAT_ELEVATOR_CAP_CLOSE * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_BOAT_ELEVATOR_CAP_CLOSE = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_BOAT_ELEVATOR_CAP_CLOSE - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: DI_HEATER_SHUTTER_OPEN = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_HEATER_SHUTTER_OPEN - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_HEATER_SHUTTER_OPEN >= (TRUE - 1.0E-6) AND
      DI_HEATER_SHUTTER_OPEN <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_HEATER_SHUTTER_OPEN >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_HEATER_SHUTTER_OPEN * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_HEATER_SHUTTER_OPEN = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_HEATER_SHUTTER_OPEN - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: DI_HEATER_SHUTTER_CLOSE = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_HEATER_SHUTTER_CLOSE - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_HEATER_SHUTTER_CLOSE >= (FALSE - 1.0E-6) AND
      DI_HEATER_SHUTTER_CLOSE <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_HEATER_SHUTTER_CLOSE >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_HEATER_SHUTTER_CLOSE * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_HEATER_SHUTTER_CLOSE = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_HEATER_SHUTTER_CLOSE - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: DI_DRY_PUMP_MP_RUN_STATUS = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_DRY_PUMP_MP_RUN_STATUS - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_DRY_PUMP_MP_RUN_STATUS >= (FALSE - 1.0E-6) AND
      DI_DRY_PUMP_MP_RUN_STATUS <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_DRY_PUMP_MP_RUN_STATUS >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_DRY_PUMP_MP_RUN_STATUS * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_DRY_PUMP_MP_RUN_STATUS = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_DRY_PUMP_MP_RUN_STATUS - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: DI_DRY_PUMP_ALARM = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_DRY_PUMP_ALARM - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_DRY_PUMP_ALARM >= (FALSE - 1.0E-6) AND
      DI_DRY_PUMP_ALARM <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_DRY_PUMP_ALARM >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_DRY_PUMP_ALARM * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_DRY_PUMP_ALARM = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_DRY_PUMP_ALARM - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: Timeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timeout <> NULL THEN
       value := Timeout^;
       // 또는 Timeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timeout) THEN
       value := Timeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timeout := ADR(targetVariable);
   IF Timeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timeout^; // NULL 체크 없음!
value := Timeout.member; // NULL 체크 없음!

✅ 안전: IF Timeout <> NULL THEN
value := Timeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timeout) THEN
value := Timeout.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: VG_Stable_Timer: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF VG_Stable_Timer <> NULL THEN
       value := VG_Stable_Timer^;
       // 또는 VG_Stable_Timer.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: VG_Stable_Timer');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(VG_Stable_Timer) THEN
       value := VG_Stable_Timer.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   VG_Stable_Timer := ADR(targetVariable);
   IF VG_Stable_Timer = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF VG_Stable_Timer = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := VG_Stable_Timer^; // NULL 체크 없음!
value := VG_Stable_Timer.member; // NULL 체크 없음!

✅ 안전: IF VG_Stable_Timer <> NULL THEN
value := VG_Stable_Timer^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(VG_Stable_Timer) THEN
value := VG_Stable_Timer.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: VG_Check_Delay_Timer: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF VG_Check_Delay_Timer <> NULL THEN
       value := VG_Check_Delay_Timer^;
       // 또는 VG_Check_Delay_Timer.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: VG_Check_Delay_Timer');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(VG_Check_Delay_Timer) THEN
       value := VG_Check_Delay_Timer.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   VG_Check_Delay_Timer := ADR(targetVariable);
   IF VG_Check_Delay_Timer = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF VG_Check_Delay_Timer = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := VG_Check_Delay_Timer^; // NULL 체크 없음!
value := VG_Check_Delay_Timer.member; // NULL 체크 없음!

✅ 안전: IF VG_Check_Delay_Timer <> NULL THEN
value := VG_Check_Delay_Timer^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(VG_Check_Delay_Timer) THEN
value := VG_Check_Delay_Timer.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: Timeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timeout <> NULL THEN
       value := Timeout^;
       // 또는 Timeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timeout) THEN
       value := Timeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timeout := ADR(targetVariable);
   IF Timeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timeout^; // NULL 체크 없음!
value := Timeout.member; // NULL 체크 없음!

✅ 안전: IF Timeout <> NULL THEN
value := Timeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timeout) THEN
value := Timeout.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: SEQ_Physical_VG01: 184줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Physical_VG01 = 184줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: DX_INF_State_Module <> eModule_Disable: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Disable - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Disable + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Disable THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Disable * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Disable THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: Mode = eMode_RCP_AutoCal: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_RCP_AutoCal) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_RCP_AutoCal - 1.0E-6) AND
      Mode <= (eMode_RCP_AutoCal + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_RCP_AutoCal THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_RCP_AutoCal * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_RCP_AutoCal THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_RCP_AutoCal) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: Mode = eMode_MNL_AutoCal: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_MNL_AutoCal) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_MNL_AutoCal - 1.0E-6) AND
      Mode <= (eMode_MNL_AutoCal + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_MNL_AutoCal THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_MNL_AutoCal * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_MNL_AutoCal THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_MNL_AutoCal) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: DX_SEQ_Driver_VG01_Ctrl = eIdle: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Driver_VG01_Ctrl - eIdle) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Driver_VG01_Ctrl >= (eIdle - 1.0E-6) AND
      DX_SEQ_Driver_VG01_Ctrl <= (eIdle + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Driver_VG01_Ctrl >= eIdle THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Driver_VG01_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eIdle * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Driver_VG01_Ctrl = eIdle THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Driver_VG01_Ctrl - eIdle) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: DX_SEQ_Driver_VG01_Ctrl = eAborted: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Driver_VG01_Ctrl - eAborted) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Driver_VG01_Ctrl >= (eAborted - 1.0E-6) AND
      DX_SEQ_Driver_VG01_Ctrl <= (eAborted + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Driver_VG01_Ctrl >= eAborted THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Driver_VG01_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAborted * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Driver_VG01_Ctrl = eAborted THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Driver_VG01_Ctrl - eAborted) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: fbAlarm[DX_VG01_AlarmID]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF DX_VG01_AlarmID >= 1 AND
      DX_VG01_AlarmID <= 10 THEN
       value := fbAlarm[DX_VG01_AlarmID];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, DX_VG01_AlarmID, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF DX_VG01_AlarmID >= ARRAY_MIN AND DX_VG01_AlarmID <= ARRAY_MAX THEN
       value := fbAlarm[DX_VG01_AlarmID];
   END_IF

예시:

❌ 위험: value := fbAlarm[DX_VG01_AlarmID]; // 범위 검사 없음!

✅ 안전: IF DX_VG01_AlarmID >= 1 AND DX_VG01_AlarmID <= 10 THEN
value := fbAlarm[DX_VG01_AlarmID];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: Timeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timeout <> NULL THEN
       value := Timeout^;
       // 또는 Timeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timeout) THEN
       value := Timeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timeout := ADR(targetVariable);
   IF Timeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timeout^; // NULL 체크 없음!
value := Timeout.member; // NULL 체크 없음!

✅ 안전: IF Timeout <> NULL THEN
value := Timeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timeout) THEN
value := Timeout.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: VG_Stable_Timer: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF VG_Stable_Timer <> NULL THEN
       value := VG_Stable_Timer^;
       // 또는 VG_Stable_Timer.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: VG_Stable_Timer');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(VG_Stable_Timer) THEN
       value := VG_Stable_Timer.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   VG_Stable_Timer := ADR(targetVariable);
   IF VG_Stable_Timer = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF VG_Stable_Timer = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := VG_Stable_Timer^; // NULL 체크 없음!
value := VG_Stable_Timer.member; // NULL 체크 없음!

✅ 안전: IF VG_Stable_Timer <> NULL THEN
value := VG_Stable_Timer^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(VG_Stable_Timer) THEN
value := VG_Stable_Timer.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: VG_Check_Delay_Timer: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF VG_Check_Delay_Timer <> NULL THEN
       value := VG_Check_Delay_Timer^;
       // 또는 VG_Check_Delay_Timer.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: VG_Check_Delay_Timer');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(VG_Check_Delay_Timer) THEN
       value := VG_Check_Delay_Timer.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   VG_Check_Delay_Timer := ADR(targetVariable);
   IF VG_Check_Delay_Timer = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF VG_Check_Delay_Timer = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := VG_Check_Delay_Timer^; // NULL 체크 없음!
value := VG_Check_Delay_Timer.member; // NULL 체크 없음!

✅ 안전: IF VG_Check_Delay_Timer <> NULL THEN
value := VG_Check_Delay_Timer^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(VG_Check_Delay_Timer) THEN
value := VG_Check_Delay_Timer.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: Timeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timeout <> NULL THEN
       value := Timeout^;
       // 또는 Timeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timeout) THEN
       value := Timeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timeout := ADR(targetVariable);
   IF Timeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timeout^; // NULL 체크 없음!
value := Timeout.member; // NULL 체크 없음!

✅ 안전: IF Timeout <> NULL THEN
value := Timeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timeout) THEN
value := Timeout.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: SEQ_Physical_VG02: 184줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Physical_VG02 = 184줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: DX_INF_State_Module <> eModule_Disable: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Disable - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Disable + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Disable THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Disable * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Disable THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: Mode = eMode_RCP_AutoCal: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_RCP_AutoCal) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_RCP_AutoCal - 1.0E-6) AND
      Mode <= (eMode_RCP_AutoCal + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_RCP_AutoCal THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_RCP_AutoCal * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_RCP_AutoCal THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_RCP_AutoCal) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: Mode = eMode_MNL_AutoCal: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_MNL_AutoCal) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_MNL_AutoCal - 1.0E-6) AND
      Mode <= (eMode_MNL_AutoCal + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_MNL_AutoCal THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_MNL_AutoCal * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_MNL_AutoCal THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_MNL_AutoCal) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: DX_SEQ_Driver_VG02_Ctrl = eIdle: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Driver_VG02_Ctrl - eIdle) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Driver_VG02_Ctrl >= (eIdle - 1.0E-6) AND
      DX_SEQ_Driver_VG02_Ctrl <= (eIdle + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Driver_VG02_Ctrl >= eIdle THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Driver_VG02_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eIdle * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Driver_VG02_Ctrl = eIdle THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Driver_VG02_Ctrl - eIdle) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: DX_SEQ_Driver_VG02_Ctrl = eAborted: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Driver_VG02_Ctrl - eAborted) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Driver_VG02_Ctrl >= (eAborted - 1.0E-6) AND
      DX_SEQ_Driver_VG02_Ctrl <= (eAborted + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Driver_VG02_Ctrl >= eAborted THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Driver_VG02_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAborted * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Driver_VG02_Ctrl = eAborted THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Driver_VG02_Ctrl - eAborted) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: fbAlarm[DX_VG02_AlarmID]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF DX_VG02_AlarmID >= 1 AND
      DX_VG02_AlarmID <= 10 THEN
       value := fbAlarm[DX_VG02_AlarmID];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, DX_VG02_AlarmID, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF DX_VG02_AlarmID >= ARRAY_MIN AND DX_VG02_AlarmID <= ARRAY_MAX THEN
       value := fbAlarm[DX_VG02_AlarmID];
   END_IF

예시:

❌ 위험: value := fbAlarm[DX_VG02_AlarmID]; // 범위 검사 없음!

✅ 안전: IF DX_VG02_AlarmID >= 1 AND DX_VG02_AlarmID <= 10 THEN
value := fbAlarm[DX_VG02_AlarmID];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: Timeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timeout <> NULL THEN
       value := Timeout^;
       // 또는 Timeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timeout) THEN
       value := Timeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timeout := ADR(targetVariable);
   IF Timeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timeout^; // NULL 체크 없음!
value := Timeout.member; // NULL 체크 없음!

✅ 안전: IF Timeout <> NULL THEN
value := Timeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timeout) THEN
value := Timeout.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: VG_Check_Delay_Timer: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF VG_Check_Delay_Timer <> NULL THEN
       value := VG_Check_Delay_Timer^;
       // 또는 VG_Check_Delay_Timer.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: VG_Check_Delay_Timer');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(VG_Check_Delay_Timer) THEN
       value := VG_Check_Delay_Timer.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   VG_Check_Delay_Timer := ADR(targetVariable);
   IF VG_Check_Delay_Timer = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF VG_Check_Delay_Timer = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := VG_Check_Delay_Timer^; // NULL 체크 없음!
value := VG_Check_Delay_Timer.member; // NULL 체크 없음!

✅ 안전: IF VG_Check_Delay_Timer <> NULL THEN
value := VG_Check_Delay_Timer^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(VG_Check_Delay_Timer) THEN
value := VG_Check_Delay_Timer.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: Timeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timeout <> NULL THEN
       value := Timeout^;
       // 또는 Timeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timeout) THEN
       value := Timeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timeout := ADR(targetVariable);
   IF Timeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timeout^; // NULL 체크 없음!
value := Timeout.member; // NULL 체크 없음!

✅ 안전: IF Timeout <> NULL THEN
value := Timeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timeout) THEN
value := Timeout.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: DX_INF_State_Module <> eModule_Disable: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Disable - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Disable + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Disable THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Disable * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Disable THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: Mode = eMode_RCP_AutoCal: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_RCP_AutoCal) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_RCP_AutoCal - 1.0E-6) AND
      Mode <= (eMode_RCP_AutoCal + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_RCP_AutoCal THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_RCP_AutoCal * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_RCP_AutoCal THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_RCP_AutoCal) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: Mode = eMode_MNL_AutoCal: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_MNL_AutoCal) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_MNL_AutoCal - 1.0E-6) AND
      Mode <= (eMode_MNL_AutoCal + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_MNL_AutoCal THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_MNL_AutoCal * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_MNL_AutoCal THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_MNL_AutoCal) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: DX_SEQ_Driver_VG03_Ctrl = eIdle: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Driver_VG03_Ctrl - eIdle) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Driver_VG03_Ctrl >= (eIdle - 1.0E-6) AND
      DX_SEQ_Driver_VG03_Ctrl <= (eIdle + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Driver_VG03_Ctrl >= eIdle THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Driver_VG03_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eIdle * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Driver_VG03_Ctrl = eIdle THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Driver_VG03_Ctrl - eIdle) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: DX_SEQ_Driver_VG03_Ctrl = eAborted: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Driver_VG03_Ctrl - eAborted) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Driver_VG03_Ctrl >= (eAborted - 1.0E-6) AND
      DX_SEQ_Driver_VG03_Ctrl <= (eAborted + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Driver_VG03_Ctrl >= eAborted THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Driver_VG03_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAborted * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Driver_VG03_Ctrl = eAborted THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Driver_VG03_Ctrl - eAborted) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: fbAlarm[DX_VG03_AlarmID]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF DX_VG03_AlarmID >= 1 AND
      DX_VG03_AlarmID <= 10 THEN
       value := fbAlarm[DX_VG03_AlarmID];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, DX_VG03_AlarmID, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF DX_VG03_AlarmID >= ARRAY_MIN AND DX_VG03_AlarmID <= ARRAY_MAX THEN
       value := fbAlarm[DX_VG03_AlarmID];
   END_IF

예시:

❌ 위험: value := fbAlarm[DX_VG03_AlarmID]; // 범위 검사 없음!

✅ 안전: IF DX_VG03_AlarmID >= 1 AND DX_VG03_AlarmID <= 10 THEN
value := fbAlarm[DX_VG03_AlarmID];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: Timeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timeout <> NULL THEN
       value := Timeout^;
       // 또는 Timeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timeout) THEN
       value := Timeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timeout := ADR(targetVariable);
   IF Timeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timeout^; // NULL 체크 없음!
value := Timeout.member; // NULL 체크 없음!

✅ 안전: IF Timeout <> NULL THEN
value := Timeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timeout) THEN
value := Timeout.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: VG_Check_Delay_Timer: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF VG_Check_Delay_Timer <> NULL THEN
       value := VG_Check_Delay_Timer^;
       // 또는 VG_Check_Delay_Timer.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: VG_Check_Delay_Timer');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(VG_Check_Delay_Timer) THEN
       value := VG_Check_Delay_Timer.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   VG_Check_Delay_Timer := ADR(targetVariable);
   IF VG_Check_Delay_Timer = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF VG_Check_Delay_Timer = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := VG_Check_Delay_Timer^; // NULL 체크 없음!
value := VG_Check_Delay_Timer.member; // NULL 체크 없음!

✅ 안전: IF VG_Check_Delay_Timer <> NULL THEN
value := VG_Check_Delay_Timer^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(VG_Check_Delay_Timer) THEN
value := VG_Check_Delay_Timer.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: Timeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timeout <> NULL THEN
       value := Timeout^;
       // 또는 Timeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timeout) THEN
       value := Timeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timeout := ADR(targetVariable);
   IF Timeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timeout^; // NULL 체크 없음!
value := Timeout.member; // NULL 체크 없음!

✅ 안전: IF Timeout <> NULL THEN
value := Timeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timeout) THEN
value := Timeout.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: DX_INF_State_Module <> eModule_Disable: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Disable - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Disable + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Disable THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Disable * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Disable THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: Mode = eMode_RCP_AutoCal: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_RCP_AutoCal) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_RCP_AutoCal - 1.0E-6) AND
      Mode <= (eMode_RCP_AutoCal + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_RCP_AutoCal THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_RCP_AutoCal * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_RCP_AutoCal THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_RCP_AutoCal) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: Mode = eMode_MNL_AutoCal: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_MNL_AutoCal) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_MNL_AutoCal - 1.0E-6) AND
      Mode <= (eMode_MNL_AutoCal + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_MNL_AutoCal THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_MNL_AutoCal * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_MNL_AutoCal THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_MNL_AutoCal) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: DX_SEQ_Driver_VG04_Ctrl = eIdle: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Driver_VG04_Ctrl - eIdle) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Driver_VG04_Ctrl >= (eIdle - 1.0E-6) AND
      DX_SEQ_Driver_VG04_Ctrl <= (eIdle + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Driver_VG04_Ctrl >= eIdle THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Driver_VG04_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eIdle * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Driver_VG04_Ctrl = eIdle THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Driver_VG04_Ctrl - eIdle) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: DX_SEQ_Driver_VG04_Ctrl = eAborted: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Driver_VG04_Ctrl - eAborted) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Driver_VG04_Ctrl >= (eAborted - 1.0E-6) AND
      DX_SEQ_Driver_VG04_Ctrl <= (eAborted + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Driver_VG04_Ctrl >= eAborted THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Driver_VG04_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAborted * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Driver_VG04_Ctrl = eAborted THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Driver_VG04_Ctrl - eAborted) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: fbAlarm[DX_VG04_AlarmID]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF DX_VG04_AlarmID >= 1 AND
      DX_VG04_AlarmID <= 10 THEN
       value := fbAlarm[DX_VG04_AlarmID];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, DX_VG04_AlarmID, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF DX_VG04_AlarmID >= ARRAY_MIN AND DX_VG04_AlarmID <= ARRAY_MAX THEN
       value := fbAlarm[DX_VG04_AlarmID];
   END_IF

예시:

❌ 위험: value := fbAlarm[DX_VG04_AlarmID]; // 범위 검사 없음!

✅ 안전: IF DX_VG04_AlarmID >= 1 AND DX_VG04_AlarmID <= 10 THEN
value := fbAlarm[DX_VG04_AlarmID];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: Timeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timeout <> NULL THEN
       value := Timeout^;
       // 또는 Timeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timeout) THEN
       value := Timeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timeout := ADR(targetVariable);
   IF Timeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timeout^; // NULL 체크 없음!
value := Timeout.member; // NULL 체크 없음!

✅ 안전: IF Timeout <> NULL THEN
value := Timeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timeout) THEN
value := Timeout.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: VG_Check_Delay_Timer: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF VG_Check_Delay_Timer <> NULL THEN
       value := VG_Check_Delay_Timer^;
       // 또는 VG_Check_Delay_Timer.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: VG_Check_Delay_Timer');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(VG_Check_Delay_Timer) THEN
       value := VG_Check_Delay_Timer.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   VG_Check_Delay_Timer := ADR(targetVariable);
   IF VG_Check_Delay_Timer = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF VG_Check_Delay_Timer = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := VG_Check_Delay_Timer^; // NULL 체크 없음!
value := VG_Check_Delay_Timer.member; // NULL 체크 없음!

✅ 안전: IF VG_Check_Delay_Timer <> NULL THEN
value := VG_Check_Delay_Timer^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(VG_Check_Delay_Timer) THEN
value := VG_Check_Delay_Timer.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: Timeout: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Timeout <> NULL THEN
       value := Timeout^;
       // 또는 Timeout.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Timeout');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Timeout) THEN
       value := Timeout.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Timeout := ADR(targetVariable);
   IF Timeout = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Timeout = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Timeout^; // NULL 체크 없음!
value := Timeout.member; // NULL 체크 없음!

✅ 안전: IF Timeout <> NULL THEN
value := Timeout^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Timeout) THEN
value := Timeout.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eRun - 1.0E-6) AND
      Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: DX_INF_State_Module <> eModule_Disable: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Module >= (eModule_Disable - 1.0E-6) AND
      DX_INF_State_Module <= (eModule_Disable + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Module >= eModule_Disable THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Module * 10.0);
   intTarget := REAL_TO_DINT(eModule_Disable * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Module = eModule_Disable THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Module - eModule_Disable) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: Mode = eMode_RCP_AutoCal: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_RCP_AutoCal) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_RCP_AutoCal - 1.0E-6) AND
      Mode <= (eMode_RCP_AutoCal + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_RCP_AutoCal THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_RCP_AutoCal * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_RCP_AutoCal THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_RCP_AutoCal) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: Mode = eMode_MNL_AutoCal: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Mode - eMode_MNL_AutoCal) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Mode >= (eMode_MNL_AutoCal - 1.0E-6) AND
      Mode <= (eMode_MNL_AutoCal + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Mode >= eMode_MNL_AutoCal THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Mode * 10.0);
   intTarget := REAL_TO_DINT(eMode_MNL_AutoCal * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Mode = eMode_MNL_AutoCal THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Mode - eMode_MNL_AutoCal) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: Ctrl = eAbort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Ctrl - eAbort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Ctrl >= (eAbort - 1.0E-6) AND
      Ctrl <= (eAbort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Ctrl >= eAbort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAbort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Ctrl = eAbort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Ctrl - eAbort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: DX_SEQ_Driver_VG05_Ctrl = eIdle: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Driver_VG05_Ctrl - eIdle) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Driver_VG05_Ctrl >= (eIdle - 1.0E-6) AND
      DX_SEQ_Driver_VG05_Ctrl <= (eIdle + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Driver_VG05_Ctrl >= eIdle THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Driver_VG05_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eIdle * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Driver_VG05_Ctrl = eIdle THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Driver_VG05_Ctrl - eIdle) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: DX_SEQ_Driver_VG05_Ctrl = eAborted: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Driver_VG05_Ctrl - eAborted) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Driver_VG05_Ctrl >= (eAborted - 1.0E-6) AND
      DX_SEQ_Driver_VG05_Ctrl <= (eAborted + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Driver_VG05_Ctrl >= eAborted THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Driver_VG05_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eAborted * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Driver_VG05_Ctrl = eAborted THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Driver_VG05_Ctrl - eAborted) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: fbAlarm[DX_VG05_AlarmID]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF DX_VG05_AlarmID >= 1 AND
      DX_VG05_AlarmID <= 10 THEN
       value := fbAlarm[DX_VG05_AlarmID];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, DX_VG05_AlarmID, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF DX_VG05_AlarmID >= ARRAY_MIN AND DX_VG05_AlarmID <= ARRAY_MAX THEN
       value := fbAlarm[DX_VG05_AlarmID];
   END_IF

예시:

❌ 위험: value := fbAlarm[DX_VG05_AlarmID]; // 범위 검사 없음!

✅ 안전: IF DX_VG05_AlarmID >= 1 AND DX_VG05_AlarmID <= 10 THEN
value := fbAlarm[DX_VG05_AlarmID];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: eIndex_RSD: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eIndex_RSD <> NULL THEN
       value := eIndex_RSD^;
       // 또는 eIndex_RSD.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eIndex_RSD');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eIndex_RSD) THEN
       value := eIndex_RSD.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eIndex_RSD := ADR(targetVariable);
   IF eIndex_RSD = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eIndex_RSD = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eIndex_RSD^; // NULL 체크 없음!
value := eIndex_RSD.member; // NULL 체크 없음!

✅ 안전: IF eIndex_RSD <> NULL THEN
value := eIndex_RSD^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eIndex_RSD) THEN
value := eIndex_RSD.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: eDesc_Use: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF eDesc_Use <> NULL THEN
       value := eDesc_Use^;
       // 또는 eDesc_Use.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: eDesc_Use');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(eDesc_Use) THEN
       value := eDesc_Use.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   eDesc_Use := ADR(targetVariable);
   IF eDesc_Use = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF eDesc_Use = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := eDesc_Use^; // NULL 체크 없음!
value := eDesc_Use.member; // NULL 체크 없음!

✅ 안전: IF eDesc_Use <> NULL THEN
value := eDesc_Use^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(eDesc_Use) THEN
value := eDesc_Use.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: SYS_DataExchange: 417줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SYS_DataExchange = 417줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DX_SEQ_Physical_Heater_Shutter_Ctrl = eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Physical_Heater_Shutter_Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Physical_Heater_Shutter_Ctrl >= (eRun - 1.0E-6) AND
      DX_SEQ_Physical_Heater_Shutter_Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Physical_Heater_Shutter_Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Physical_Heater_Shutter_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Physical_Heater_Shutter_Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Physical_Heater_Shutter_Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_HEATER_SHUTTER_CLOSE = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_HEATER_SHUTTER_CLOSE - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_HEATER_SHUTTER_CLOSE >= (TRUE - 1.0E-6) AND
      DI_HEATER_SHUTTER_CLOSE <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_HEATER_SHUTTER_CLOSE >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_HEATER_SHUTTER_CLOSE * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_HEATER_SHUTTER_CLOSE = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_HEATER_SHUTTER_CLOSE - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_HEATER_SHUTTER_OPEN = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_HEATER_SHUTTER_OPEN - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_HEATER_SHUTTER_OPEN >= (FALSE - 1.0E-6) AND
      DI_HEATER_SHUTTER_OPEN <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_HEATER_SHUTTER_OPEN >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_HEATER_SHUTTER_OPEN * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_HEATER_SHUTTER_OPEN = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_HEATER_SHUTTER_OPEN - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_HEATER_SHUTTER_CLOSE = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_HEATER_SHUTTER_CLOSE - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_HEATER_SHUTTER_CLOSE >= (FALSE - 1.0E-6) AND
      DI_HEATER_SHUTTER_CLOSE <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_HEATER_SHUTTER_CLOSE >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_HEATER_SHUTTER_CLOSE * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_HEATER_SHUTTER_CLOSE = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_HEATER_SHUTTER_CLOSE - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_HEATER_SHUTTER_OPEN = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_HEATER_SHUTTER_OPEN - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_HEATER_SHUTTER_OPEN >= (TRUE - 1.0E-6) AND
      DI_HEATER_SHUTTER_OPEN <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_HEATER_SHUTTER_OPEN >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_HEATER_SHUTTER_OPEN * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_HEATER_SHUTTER_OPEN = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_HEATER_SHUTTER_OPEN - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DX_SEQ_Physical_Boat_Elevator_Ctrl <> eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Physical_Boat_Elevator_Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Physical_Boat_Elevator_Ctrl >= (eRun - 1.0E-6) AND
      DX_SEQ_Physical_Boat_Elevator_Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Physical_Boat_Elevator_Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Physical_Boat_Elevator_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Physical_Boat_Elevator_Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Physical_Boat_Elevator_Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_BOAT_ELEVATOR_HOME_POSITION = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_BOAT_ELEVATOR_HOME_POSITION - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_BOAT_ELEVATOR_HOME_POSITION >= (TRUE - 1.0E-6) AND
      DI_BOAT_ELEVATOR_HOME_POSITION <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_BOAT_ELEVATOR_HOME_POSITION >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_BOAT_ELEVATOR_HOME_POSITION * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_BOAT_ELEVATOR_HOME_POSITION = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_BOAT_ELEVATOR_HOME_POSITION - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_BOAT_ELEVATOR_CAP_CLOSE = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_BOAT_ELEVATOR_CAP_CLOSE - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_BOAT_ELEVATOR_CAP_CLOSE >= (TRUE - 1.0E-6) AND
      DI_BOAT_ELEVATOR_CAP_CLOSE <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_BOAT_ELEVATOR_CAP_CLOSE >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_BOAT_ELEVATOR_CAP_CLOSE * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_BOAT_ELEVATOR_CAP_CLOSE = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_BOAT_ELEVATOR_CAP_CLOSE - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DX_SEQ_Physical_LoadLock_Ctrl <> eRun: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Physical_LoadLock_Ctrl - eRun) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Physical_LoadLock_Ctrl >= (eRun - 1.0E-6) AND
      DX_SEQ_Physical_LoadLock_Ctrl <= (eRun + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Physical_LoadLock_Ctrl >= eRun THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Physical_LoadLock_Ctrl * 10.0);
   intTarget := REAL_TO_DINT(eRun * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Physical_LoadLock_Ctrl = eRun THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Physical_LoadLock_Ctrl - eRun) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DX_CFG_LDA_ATM_SLIT_Damper = 1: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_CFG_LDA_ATM_SLIT_Damper - 1) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_CFG_LDA_ATM_SLIT_Damper >= (1 - 1.0E-6) AND
      DX_CFG_LDA_ATM_SLIT_Damper <= (1 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_CFG_LDA_ATM_SLIT_Damper >= 1 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_CFG_LDA_ATM_SLIT_Damper * 10.0);
   intTarget := REAL_TO_DINT(1 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_CFG_LDA_ATM_SLIT_Damper = 1 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_CFG_LDA_ATM_SLIT_Damper - 1) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_SLIT_DAMPER_OPEN_STATUS = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_SLIT_DAMPER_OPEN_STATUS - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_SLIT_DAMPER_OPEN_STATUS >= (TRUE - 1.0E-6) AND
      DI_SLIT_DAMPER_OPEN_STATUS <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_SLIT_DAMPER_OPEN_STATUS >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_SLIT_DAMPER_OPEN_STATUS * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_SLIT_DAMPER_OPEN_STATUS = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_SLIT_DAMPER_OPEN_STATUS - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_SLIT_DAMPER_CLOSE_STATUS = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_SLIT_DAMPER_CLOSE_STATUS - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_SLIT_DAMPER_CLOSE_STATUS >= (FALSE - 1.0E-6) AND
      DI_SLIT_DAMPER_CLOSE_STATUS <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_SLIT_DAMPER_CLOSE_STATUS >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_SLIT_DAMPER_CLOSE_STATUS * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_SLIT_DAMPER_CLOSE_STATUS = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_SLIT_DAMPER_CLOSE_STATUS - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DX_CFG_LDA_ATM_SLIT_Damper <> 1: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_CFG_LDA_ATM_SLIT_Damper - 1) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_CFG_LDA_ATM_SLIT_Damper >= (1 - 1.0E-6) AND
      DX_CFG_LDA_ATM_SLIT_Damper <= (1 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_CFG_LDA_ATM_SLIT_Damper >= 1 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_CFG_LDA_ATM_SLIT_Damper * 10.0);
   intTarget := REAL_TO_DINT(1 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_CFG_LDA_ATM_SLIT_Damper = 1 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_CFG_LDA_ATM_SLIT_Damper - 1) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_SLIT_DAMPER_OPEN_STATUS = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_SLIT_DAMPER_OPEN_STATUS - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_SLIT_DAMPER_OPEN_STATUS >= (FALSE - 1.0E-6) AND
      DI_SLIT_DAMPER_OPEN_STATUS <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_SLIT_DAMPER_OPEN_STATUS >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_SLIT_DAMPER_OPEN_STATUS * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_SLIT_DAMPER_OPEN_STATUS = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_SLIT_DAMPER_OPEN_STATUS - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_SLIT_DAMPER_CLOSE_STATUS = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_SLIT_DAMPER_CLOSE_STATUS - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_SLIT_DAMPER_CLOSE_STATUS >= (TRUE - 1.0E-6) AND
      DI_SLIT_DAMPER_CLOSE_STATUS <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_SLIT_DAMPER_CLOSE_STATUS >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_SLIT_DAMPER_CLOSE_STATUS * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_SLIT_DAMPER_CLOSE_STATUS = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_SLIT_DAMPER_CLOSE_STATUS - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DX_CFG_LDA_ATM_BTM_Damper = 1: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_CFG_LDA_ATM_BTM_Damper - 1) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_CFG_LDA_ATM_BTM_Damper >= (1 - 1.0E-6) AND
      DX_CFG_LDA_ATM_BTM_Damper <= (1 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_CFG_LDA_ATM_BTM_Damper >= 1 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_CFG_LDA_ATM_BTM_Damper * 10.0);
   intTarget := REAL_TO_DINT(1 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_CFG_LDA_ATM_BTM_Damper = 1 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_CFG_LDA_ATM_BTM_Damper - 1) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_AV69_OPEN_STATUS = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_AV69_OPEN_STATUS - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_AV69_OPEN_STATUS >= (TRUE - 1.0E-6) AND
      DI_AV69_OPEN_STATUS <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_AV69_OPEN_STATUS >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_AV69_OPEN_STATUS * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_AV69_OPEN_STATUS = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_AV69_OPEN_STATUS - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_AV69_CLOSE_STATUS = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_AV69_CLOSE_STATUS - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_AV69_CLOSE_STATUS >= (FALSE - 1.0E-6) AND
      DI_AV69_CLOSE_STATUS <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_AV69_CLOSE_STATUS >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_AV69_CLOSE_STATUS * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_AV69_CLOSE_STATUS = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_AV69_CLOSE_STATUS - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DX_CFG_LDA_ATM_BTM_Damper <> 1: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_CFG_LDA_ATM_BTM_Damper - 1) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_CFG_LDA_ATM_BTM_Damper >= (1 - 1.0E-6) AND
      DX_CFG_LDA_ATM_BTM_Damper <= (1 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_CFG_LDA_ATM_BTM_Damper >= 1 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_CFG_LDA_ATM_BTM_Damper * 10.0);
   intTarget := REAL_TO_DINT(1 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_CFG_LDA_ATM_BTM_Damper = 1 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_CFG_LDA_ATM_BTM_Damper - 1) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_AV69_OPEN_STATUS = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_AV69_OPEN_STATUS - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_AV69_OPEN_STATUS >= (FALSE - 1.0E-6) AND
      DI_AV69_OPEN_STATUS <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_AV69_OPEN_STATUS >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_AV69_OPEN_STATUS * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_AV69_OPEN_STATUS = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_AV69_OPEN_STATUS - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_AV69_CLOSE_STATUS = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_AV69_CLOSE_STATUS - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_AV69_CLOSE_STATUS >= (TRUE - 1.0E-6) AND
      DI_AV69_CLOSE_STATUS <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_AV69_CLOSE_STATUS >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_AV69_CLOSE_STATUS * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_AV69_CLOSE_STATUS = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_AV69_CLOSE_STATUS - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DX_CFG_LDA_ATM_INTAKE = 1: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_CFG_LDA_ATM_INTAKE - 1) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_CFG_LDA_ATM_INTAKE >= (1 - 1.0E-6) AND
      DX_CFG_LDA_ATM_INTAKE <= (1 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_CFG_LDA_ATM_INTAKE >= 1 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_CFG_LDA_ATM_INTAKE * 10.0);
   intTarget := REAL_TO_DINT(1 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_CFG_LDA_ATM_INTAKE = 1 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_CFG_LDA_ATM_INTAKE - 1) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_LOADING_AREA_INTAKE01_OPEN = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_LOADING_AREA_INTAKE01_OPEN - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_LOADING_AREA_INTAKE01_OPEN >= (TRUE - 1.0E-6) AND
      DI_LOADING_AREA_INTAKE01_OPEN <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_LOADING_AREA_INTAKE01_OPEN >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_LOADING_AREA_INTAKE01_OPEN * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_LOADING_AREA_INTAKE01_OPEN = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_LOADING_AREA_INTAKE01_OPEN - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_LOADING_AREA_INTAKE01_CLOSE = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_LOADING_AREA_INTAKE01_CLOSE - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_LOADING_AREA_INTAKE01_CLOSE >= (FALSE - 1.0E-6) AND
      DI_LOADING_AREA_INTAKE01_CLOSE <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_LOADING_AREA_INTAKE01_CLOSE >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_LOADING_AREA_INTAKE01_CLOSE * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_LOADING_AREA_INTAKE01_CLOSE = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_LOADING_AREA_INTAKE01_CLOSE - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_LOADING_AREA_INTAKE02_OPEN = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_LOADING_AREA_INTAKE02_OPEN - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_LOADING_AREA_INTAKE02_OPEN >= (TRUE - 1.0E-6) AND
      DI_LOADING_AREA_INTAKE02_OPEN <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_LOADING_AREA_INTAKE02_OPEN >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_LOADING_AREA_INTAKE02_OPEN * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_LOADING_AREA_INTAKE02_OPEN = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_LOADING_AREA_INTAKE02_OPEN - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_LOADING_AREA_INTAKE02_CLOSE = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_LOADING_AREA_INTAKE02_CLOSE - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_LOADING_AREA_INTAKE02_CLOSE >= (FALSE - 1.0E-6) AND
      DI_LOADING_AREA_INTAKE02_CLOSE <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_LOADING_AREA_INTAKE02_CLOSE >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_LOADING_AREA_INTAKE02_CLOSE * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_LOADING_AREA_INTAKE02_CLOSE = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_LOADING_AREA_INTAKE02_CLOSE - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DX_CFG_LDA_ATM_INTAKE <> 1: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_CFG_LDA_ATM_INTAKE - 1) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_CFG_LDA_ATM_INTAKE >= (1 - 1.0E-6) AND
      DX_CFG_LDA_ATM_INTAKE <= (1 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_CFG_LDA_ATM_INTAKE >= 1 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_CFG_LDA_ATM_INTAKE * 10.0);
   intTarget := REAL_TO_DINT(1 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_CFG_LDA_ATM_INTAKE = 1 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_CFG_LDA_ATM_INTAKE - 1) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_LOADING_AREA_INTAKE01_OPEN = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_LOADING_AREA_INTAKE01_OPEN - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_LOADING_AREA_INTAKE01_OPEN >= (FALSE - 1.0E-6) AND
      DI_LOADING_AREA_INTAKE01_OPEN <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_LOADING_AREA_INTAKE01_OPEN >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_LOADING_AREA_INTAKE01_OPEN * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_LOADING_AREA_INTAKE01_OPEN = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_LOADING_AREA_INTAKE01_OPEN - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_LOADING_AREA_INTAKE01_CLOSE = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_LOADING_AREA_INTAKE01_CLOSE - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_LOADING_AREA_INTAKE01_CLOSE >= (TRUE - 1.0E-6) AND
      DI_LOADING_AREA_INTAKE01_CLOSE <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_LOADING_AREA_INTAKE01_CLOSE >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_LOADING_AREA_INTAKE01_CLOSE * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_LOADING_AREA_INTAKE01_CLOSE = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_LOADING_AREA_INTAKE01_CLOSE - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_LOADING_AREA_INTAKE02_OPEN = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_LOADING_AREA_INTAKE02_OPEN - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_LOADING_AREA_INTAKE02_OPEN >= (FALSE - 1.0E-6) AND
      DI_LOADING_AREA_INTAKE02_OPEN <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_LOADING_AREA_INTAKE02_OPEN >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_LOADING_AREA_INTAKE02_OPEN * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_LOADING_AREA_INTAKE02_OPEN = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_LOADING_AREA_INTAKE02_OPEN - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_LOADING_AREA_INTAKE02_CLOSE = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_LOADING_AREA_INTAKE02_CLOSE - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_LOADING_AREA_INTAKE02_CLOSE >= (TRUE - 1.0E-6) AND
      DI_LOADING_AREA_INTAKE02_CLOSE <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_LOADING_AREA_INTAKE02_CLOSE >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_LOADING_AREA_INTAKE02_CLOSE * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_LOADING_AREA_INTAKE02_CLOSE = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_LOADING_AREA_INTAKE02_CLOSE - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_ATM_INTAKE_FRONT_VALVE_OPEN_STATUS = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_ATM_INTAKE_FRONT_VALVE_OPEN_STATUS - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_ATM_INTAKE_FRONT_VALVE_OPEN_STATUS >= (TRUE - 1.0E-6) AND
      DI_ATM_INTAKE_FRONT_VALVE_OPEN_STATUS <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_ATM_INTAKE_FRONT_VALVE_OPEN_STATUS >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_ATM_INTAKE_FRONT_VALVE_OPEN_STATUS * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_ATM_INTAKE_FRONT_VALVE_OPEN_STATUS = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_ATM_INTAKE_FRONT_VALVE_OPEN_STATUS - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_ATM_INTAKE_FRONT_VALVE_CLOSE_STATUS = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_ATM_INTAKE_FRONT_VALVE_CLOSE_STATUS - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_ATM_INTAKE_FRONT_VALVE_CLOSE_STATUS >= (FALSE - 1.0E-6) AND
      DI_ATM_INTAKE_FRONT_VALVE_CLOSE_STATUS <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_ATM_INTAKE_FRONT_VALVE_CLOSE_STATUS >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_ATM_INTAKE_FRONT_VALVE_CLOSE_STATUS * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_ATM_INTAKE_FRONT_VALVE_CLOSE_STATUS = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_ATM_INTAKE_FRONT_VALVE_CLOSE_STATUS - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_ATM_INTAKE_REAR_OPEN_STATUS = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_ATM_INTAKE_REAR_OPEN_STATUS - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_ATM_INTAKE_REAR_OPEN_STATUS >= (TRUE - 1.0E-6) AND
      DI_ATM_INTAKE_REAR_OPEN_STATUS <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_ATM_INTAKE_REAR_OPEN_STATUS >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_ATM_INTAKE_REAR_OPEN_STATUS * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_ATM_INTAKE_REAR_OPEN_STATUS = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_ATM_INTAKE_REAR_OPEN_STATUS - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_ATM_INTAKE_REAR_CLOSE_STATUS = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_ATM_INTAKE_REAR_CLOSE_STATUS - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_ATM_INTAKE_REAR_CLOSE_STATUS >= (FALSE - 1.0E-6) AND
      DI_ATM_INTAKE_REAR_CLOSE_STATUS <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_ATM_INTAKE_REAR_CLOSE_STATUS >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_ATM_INTAKE_REAR_CLOSE_STATUS * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_ATM_INTAKE_REAR_CLOSE_STATUS = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_ATM_INTAKE_REAR_CLOSE_STATUS - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_AV81_OPEN = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_AV81_OPEN - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_AV81_OPEN >= (FALSE - 1.0E-6) AND
      DI_AV81_OPEN <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_AV81_OPEN >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_AV81_OPEN * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_AV81_OPEN = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_AV81_OPEN - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DI_AV82_OPEN = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DI_AV82_OPEN - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DI_AV82_OPEN >= (FALSE - 1.0E-6) AND
      DI_AV82_OPEN <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DI_AV82_OPEN >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DI_AV82_OPEN * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DI_AV82_OPEN = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DI_AV82_OPEN - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DX_CFG_LDA_ATM_RSD_Action = DI_RSD_Damper: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_CFG_LDA_ATM_RSD_Action - DI_RSD_Damper) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_CFG_LDA_ATM_RSD_Action >= (DI_RSD_Damper - 1.0E-6) AND
      DX_CFG_LDA_ATM_RSD_Action <= (DI_RSD_Damper + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_CFG_LDA_ATM_RSD_Action >= DI_RSD_Damper THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_CFG_LDA_ATM_RSD_Action * 10.0);
   intTarget := REAL_TO_DINT(DI_RSD_Damper * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_CFG_LDA_ATM_RSD_Action = DI_RSD_Damper THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_CFG_LDA_ATM_RSD_Action - DI_RSD_Damper) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: DX_CFG_RSD_Use[eIndex_RSD.eLDA_EXH]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF eIndex_RSD.eLDA_EXH >= 1 AND
      eIndex_RSD.eLDA_EXH <= 10 THEN
       value := DX_CFG_RSD_Use[eIndex_RSD.eLDA_EXH];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, eIndex_RSD.eLDA_EXH, 10);
   value := DX_CFG_RSD_Use[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF eIndex_RSD.eLDA_EXH >= ARRAY_MIN AND eIndex_RSD.eLDA_EXH <= ARRAY_MAX THEN
       value := DX_CFG_RSD_Use[eIndex_RSD.eLDA_EXH];
   END_IF

예시:

❌ 위험: value := DX_CFG_RSD_Use[eIndex_RSD.eLDA_EXH]; // 범위 검사 없음!

✅ 안전: IF eIndex_RSD.eLDA_EXH >= 1 AND eIndex_RSD.eLDA_EXH <= 10 THEN
value := DX_CFG_RSD_Use[eIndex_RSD.eLDA_EXH];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Input.TcPOU:1

설명: SYS_Input: 405줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SYS_Input = 405줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: TimeOut: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF TimeOut <> NULL THEN
       value := TimeOut^;
       // 또는 TimeOut.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: TimeOut');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(TimeOut) THEN
       value := TimeOut.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   TimeOut := ADR(targetVariable);
   IF TimeOut = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF TimeOut = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := TimeOut^; // NULL 체크 없음!
value := TimeOut.member; // NULL 체크 없음!

✅ 안전: IF TimeOut <> NULL THEN
value := TimeOut^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(TimeOut) THEN
value := TimeOut.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitRead: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitRead <> NULL THEN
       value := fbAlarmLimitRead^;
       // 또는 fbAlarmLimitRead.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitRead');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitRead) THEN
       value := fbAlarmLimitRead.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitRead := ADR(targetVariable);
   IF fbAlarmLimitRead = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitRead = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitRead^; // NULL 체크 없음!
value := fbAlarmLimitRead.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitRead <> NULL THEN
value := fbAlarmLimitRead^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitRead) THEN
value := fbAlarmLimitRead.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitWrite <> NULL THEN
       value := fbAlarmLimitWrite^;
       // 또는 fbAlarmLimitWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitWrite) THEN
       value := fbAlarmLimitWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitWrite := ADR(targetVariable);
   IF fbAlarmLimitWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitWrite^; // NULL 체크 없음!
value := fbAlarmLimitWrite.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitWrite <> NULL THEN
value := fbAlarmLimitWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitWrite) THEN
value := fbAlarmLimitWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitWrite <> NULL THEN
       value := fbAlarmLimitWrite^;
       // 또는 fbAlarmLimitWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitWrite) THEN
       value := fbAlarmLimitWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitWrite := ADR(targetVariable);
   IF fbAlarmLimitWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitWrite^; // NULL 체크 없음!
value := fbAlarmLimitWrite.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitWrite <> NULL THEN
value := fbAlarmLimitWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitWrite) THEN
value := fbAlarmLimitWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitWrite <> NULL THEN
       value := fbAlarmLimitWrite^;
       // 또는 fbAlarmLimitWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitWrite) THEN
       value := fbAlarmLimitWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitWrite := ADR(targetVariable);
   IF fbAlarmLimitWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitWrite^; // NULL 체크 없음!
value := fbAlarmLimitWrite.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitWrite <> NULL THEN
value := fbAlarmLimitWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitWrite) THEN
value := fbAlarmLimitWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitWrite <> NULL THEN
       value := fbAlarmLimitWrite^;
       // 또는 fbAlarmLimitWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitWrite) THEN
       value := fbAlarmLimitWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitWrite := ADR(targetVariable);
   IF fbAlarmLimitWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitWrite^; // NULL 체크 없음!
value := fbAlarmLimitWrite.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitWrite <> NULL THEN
value := fbAlarmLimitWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitWrite) THEN
value := fbAlarmLimitWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitWrite <> NULL THEN
       value := fbAlarmLimitWrite^;
       // 또는 fbAlarmLimitWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitWrite) THEN
       value := fbAlarmLimitWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitWrite := ADR(targetVariable);
   IF fbAlarmLimitWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitWrite^; // NULL 체크 없음!
value := fbAlarmLimitWrite.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitWrite <> NULL THEN
value := fbAlarmLimitWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitWrite) THEN
value := fbAlarmLimitWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitWrite <> NULL THEN
       value := fbAlarmLimitWrite^;
       // 또는 fbAlarmLimitWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitWrite) THEN
       value := fbAlarmLimitWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitWrite := ADR(targetVariable);
   IF fbAlarmLimitWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitWrite^; // NULL 체크 없음!
value := fbAlarmLimitWrite.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitWrite <> NULL THEN
value := fbAlarmLimitWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitWrite) THEN
value := fbAlarmLimitWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitWrite <> NULL THEN
       value := fbAlarmLimitWrite^;
       // 또는 fbAlarmLimitWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitWrite) THEN
       value := fbAlarmLimitWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitWrite := ADR(targetVariable);
   IF fbAlarmLimitWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitWrite^; // NULL 체크 없음!
value := fbAlarmLimitWrite.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitWrite <> NULL THEN
value := fbAlarmLimitWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitWrite) THEN
value := fbAlarmLimitWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitWrite <> NULL THEN
       value := fbAlarmLimitWrite^;
       // 또는 fbAlarmLimitWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitWrite) THEN
       value := fbAlarmLimitWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitWrite := ADR(targetVariable);
   IF fbAlarmLimitWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitWrite^; // NULL 체크 없음!
value := fbAlarmLimitWrite.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitWrite <> NULL THEN
value := fbAlarmLimitWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitWrite) THEN
value := fbAlarmLimitWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitWrite <> NULL THEN
       value := fbAlarmLimitWrite^;
       // 또는 fbAlarmLimitWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitWrite) THEN
       value := fbAlarmLimitWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitWrite := ADR(targetVariable);
   IF fbAlarmLimitWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitWrite^; // NULL 체크 없음!
value := fbAlarmLimitWrite.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitWrite <> NULL THEN
value := fbAlarmLimitWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitWrite) THEN
value := fbAlarmLimitWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitWrite <> NULL THEN
       value := fbAlarmLimitWrite^;
       // 또는 fbAlarmLimitWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitWrite) THEN
       value := fbAlarmLimitWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitWrite := ADR(targetVariable);
   IF fbAlarmLimitWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitWrite^; // NULL 체크 없음!
value := fbAlarmLimitWrite.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitWrite <> NULL THEN
value := fbAlarmLimitWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitWrite) THEN
value := fbAlarmLimitWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitWrite <> NULL THEN
       value := fbAlarmLimitWrite^;
       // 또는 fbAlarmLimitWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitWrite) THEN
       value := fbAlarmLimitWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitWrite := ADR(targetVariable);
   IF fbAlarmLimitWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitWrite^; // NULL 체크 없음!
value := fbAlarmLimitWrite.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitWrite <> NULL THEN
value := fbAlarmLimitWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitWrite) THEN
value := fbAlarmLimitWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitWrite <> NULL THEN
       value := fbAlarmLimitWrite^;
       // 또는 fbAlarmLimitWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitWrite) THEN
       value := fbAlarmLimitWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitWrite := ADR(targetVariable);
   IF fbAlarmLimitWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitWrite^; // NULL 체크 없음!
value := fbAlarmLimitWrite.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitWrite <> NULL THEN
value := fbAlarmLimitWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitWrite) THEN
value := fbAlarmLimitWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitRead: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitRead <> NULL THEN
       value := fbAlarmLimitRead^;
       // 또는 fbAlarmLimitRead.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitRead');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitRead) THEN
       value := fbAlarmLimitRead.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitRead := ADR(targetVariable);
   IF fbAlarmLimitRead = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitRead = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitRead^; // NULL 체크 없음!
value := fbAlarmLimitRead.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitRead <> NULL THEN
value := fbAlarmLimitRead^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitRead) THEN
value := fbAlarmLimitRead.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitRead: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitRead <> NULL THEN
       value := fbAlarmLimitRead^;
       // 또는 fbAlarmLimitRead.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitRead');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitRead) THEN
       value := fbAlarmLimitRead.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitRead := ADR(targetVariable);
   IF fbAlarmLimitRead = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitRead = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitRead^; // NULL 체크 없음!
value := fbAlarmLimitRead.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitRead <> NULL THEN
value := fbAlarmLimitRead^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitRead) THEN
value := fbAlarmLimitRead.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitRead: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitRead <> NULL THEN
       value := fbAlarmLimitRead^;
       // 또는 fbAlarmLimitRead.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitRead');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitRead) THEN
       value := fbAlarmLimitRead.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitRead := ADR(targetVariable);
   IF fbAlarmLimitRead = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitRead = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitRead^; // NULL 체크 없음!
value := fbAlarmLimitRead.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitRead <> NULL THEN
value := fbAlarmLimitRead^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitRead) THEN
value := fbAlarmLimitRead.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitRead: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitRead <> NULL THEN
       value := fbAlarmLimitRead^;
       // 또는 fbAlarmLimitRead.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitRead');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitRead) THEN
       value := fbAlarmLimitRead.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitRead := ADR(targetVariable);
   IF fbAlarmLimitRead = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitRead = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitRead^; // NULL 체크 없음!
value := fbAlarmLimitRead.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitRead <> NULL THEN
value := fbAlarmLimitRead^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitRead) THEN
value := fbAlarmLimitRead.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitRead: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitRead <> NULL THEN
       value := fbAlarmLimitRead^;
       // 또는 fbAlarmLimitRead.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitRead');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitRead) THEN
       value := fbAlarmLimitRead.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitRead := ADR(targetVariable);
   IF fbAlarmLimitRead = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitRead = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitRead^; // NULL 체크 없음!
value := fbAlarmLimitRead.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitRead <> NULL THEN
value := fbAlarmLimitRead^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitRead) THEN
value := fbAlarmLimitRead.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitRead: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitRead <> NULL THEN
       value := fbAlarmLimitRead^;
       // 또는 fbAlarmLimitRead.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitRead');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitRead) THEN
       value := fbAlarmLimitRead.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitRead := ADR(targetVariable);
   IF fbAlarmLimitRead = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitRead = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitRead^; // NULL 체크 없음!
value := fbAlarmLimitRead.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitRead <> NULL THEN
value := fbAlarmLimitRead^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitRead) THEN
value := fbAlarmLimitRead.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitRead: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitRead <> NULL THEN
       value := fbAlarmLimitRead^;
       // 또는 fbAlarmLimitRead.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitRead');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitRead) THEN
       value := fbAlarmLimitRead.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitRead := ADR(targetVariable);
   IF fbAlarmLimitRead = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitRead = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitRead^; // NULL 체크 없음!
value := fbAlarmLimitRead.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitRead <> NULL THEN
value := fbAlarmLimitRead^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitRead) THEN
value := fbAlarmLimitRead.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarmLimitRead: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbAlarmLimitRead <> NULL THEN
       value := fbAlarmLimitRead^;
       // 또는 fbAlarmLimitRead.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbAlarmLimitRead');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbAlarmLimitRead) THEN
       value := fbAlarmLimitRead.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbAlarmLimitRead := ADR(targetVariable);
   IF fbAlarmLimitRead = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbAlarmLimitRead = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbAlarmLimitRead^; // NULL 체크 없음!
value := fbAlarmLimitRead.member; // NULL 체크 없음!

✅ 안전: IF fbAlarmLimitRead <> NULL THEN
value := fbAlarmLimitRead^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbAlarmLimitRead) THEN
value := fbAlarmLimitRead.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: SYS_MFC_Self_Diagnosis: 166줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SYS_MFC_Self_Diagnosis = 166줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: DX_CFG_MFC_PartsPara_Log_Use = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_CFG_MFC_PartsPara_Log_Use - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_CFG_MFC_PartsPara_Log_Use >= (TRUE - 1.0E-6) AND
      DX_CFG_MFC_PartsPara_Log_Use <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_CFG_MFC_PartsPara_Log_Use >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_CFG_MFC_PartsPara_Log_Use * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_CFG_MFC_PartsPara_Log_Use = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_CFG_MFC_PartsPara_Log_Use - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: Step <> 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Step - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Step >= (0 - 1.0E-6) AND
      Step <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Step >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Step * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Step = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Step - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: LogEvent <> 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(LogEvent - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF LogEvent >= (0 - 1.0E-6) AND
      LogEvent <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF LogEvent >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(LogEvent * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF LogEvent = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(LogEvent - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: bBusy = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(bBusy - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF bBusy >= (TRUE - 1.0E-6) AND
      bBusy <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF bBusy >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(bBusy * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF bBusy = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(bBusy - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: bError = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(bError - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF bError >= (TRUE - 1.0E-6) AND
      bError <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF bError >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(bError * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF bError = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(bError - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: bBusy = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(bBusy - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF bBusy >= (FALSE - 1.0E-6) AND
      bBusy <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF bBusy >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(bBusy * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF bBusy = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(bBusy - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: bBusy = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(bBusy - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF bBusy >= (TRUE - 1.0E-6) AND
      bBusy <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF bBusy >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(bBusy * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF bBusy = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(bBusy - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: bError = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(bError - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF bError >= (TRUE - 1.0E-6) AND
      bError <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF bError >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(bError * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF bError = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(bError - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: ioNetID_MFC[idx]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF idx >= 1 AND
      idx <= 10 THEN
       value := ioNetID_MFC[idx];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, idx, 10);
   value := ioNetID_MFC[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF idx >= ARRAY_MIN AND idx <= ARRAY_MAX THEN
       value := ioNetID_MFC[idx];
   END_IF

예시:

❌ 위험: value := ioNetID_MFC[idx]; // 범위 검사 없음!

✅ 안전: IF idx >= 1 AND idx <= 10 THEN
value := ioNetID_MFC[idx];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: MFC_Port_Addr[idx]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF idx >= 1 AND
      idx <= 10 THEN
       value := MFC_Port_Addr[idx];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, idx, 10);
   value := MFC_Port_Addr[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF idx >= ARRAY_MIN AND idx <= ARRAY_MAX THEN
       value := MFC_Port_Addr[idx];
   END_IF

예시:

❌ 위험: value := MFC_Port_Addr[idx]; // 범위 검사 없음!

✅ 안전: IF idx >= 1 AND idx <= 10 THEN
value := MFC_Port_Addr[idx];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: ioNetID_MFC[idx]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF idx >= 1 AND
      idx <= 10 THEN
       value := ioNetID_MFC[idx];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, idx, 10);
   value := ioNetID_MFC[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF idx >= ARRAY_MIN AND idx <= ARRAY_MAX THEN
       value := ioNetID_MFC[idx];
   END_IF

예시:

❌ 위험: value := ioNetID_MFC[idx]; // 범위 검사 없음!

✅ 안전: IF idx >= 1 AND idx <= 10 THEN
value := ioNetID_MFC[idx];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: MFC_Port_Addr[idx]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF idx >= 1 AND
      idx <= 10 THEN
       value := MFC_Port_Addr[idx];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, idx, 10);
   value := MFC_Port_Addr[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF idx >= ARRAY_MIN AND idx <= ARRAY_MAX THEN
       value := MFC_Port_Addr[idx];
   END_IF

예시:

❌ 위험: value := MFC_Port_Addr[idx]; // 범위 검사 없음!

✅ 안전: IF idx >= 1 AND idx <= 10 THEN
value := MFC_Port_Addr[idx];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarm[10018 + ( idx - 1)*20]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 10018 + ( idx - 1)*20 >= 1 AND
      10018 + ( idx - 1)*20 <= 10 THEN
       value := fbAlarm[10018 + ( idx - 1)*20];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 10018 + ( idx - 1)*20, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 10018 + ( idx - 1)*20 >= ARRAY_MIN AND 10018 + ( idx - 1)*20 <= ARRAY_MAX THEN
       value := fbAlarm[10018 + ( idx - 1)*20];
   END_IF

예시:

❌ 위험: value := fbAlarm[10018 + ( idx - 1)*20]; // 범위 검사 없음!

✅ 안전: IF 10018 + ( idx - 1)*20 >= 1 AND 10018 + ( idx - 1)*20 <= 10 THEN
value := fbAlarm[10018 + ( idx - 1)*20];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: ioMODULE_MFC_OPStates[idx]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF idx >= 1 AND
      idx <= 10 THEN
       value := ioMODULE_MFC_OPStates[idx];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, idx, 10);
   value := ioMODULE_MFC_OPStates[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF idx >= ARRAY_MIN AND idx <= ARRAY_MAX THEN
       value := ioMODULE_MFC_OPStates[idx];
   END_IF

예시:

❌ 위험: value := ioMODULE_MFC_OPStates[idx]; // 범위 검사 없음!

✅ 안전: IF idx >= 1 AND idx <= 10 THEN
value := ioMODULE_MFC_OPStates[idx];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: pPartsPara[idx]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF idx >= 1 AND
      idx <= 10 THEN
       value := pPartsPara[idx];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, idx, 10);
   value := pPartsPara[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF idx >= ARRAY_MIN AND idx <= ARRAY_MAX THEN
       value := pPartsPara[idx];
   END_IF

예시:

❌ 위험: value := pPartsPara[idx]; // 범위 검사 없음!

✅ 안전: IF idx >= 1 AND idx <= 10 THEN
value := pPartsPara[idx];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: AX_G_LIFE_Alarm_Limit[idx]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF idx >= 1 AND
      idx <= 10 THEN
       value := AX_G_LIFE_Alarm_Limit[idx];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, idx, 10);
   value := AX_G_LIFE_Alarm_Limit[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF idx >= ARRAY_MIN AND idx <= ARRAY_MAX THEN
       value := AX_G_LIFE_Alarm_Limit[idx];
   END_IF

예시:

❌ 위험: value := AX_G_LIFE_Alarm_Limit[idx]; // 범위 검사 없음!

✅ 안전: IF idx >= 1 AND idx <= 10 THEN
value := AX_G_LIFE_Alarm_Limit[idx];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: Backup_DiagPartsPara[idx]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF idx >= 1 AND
      idx <= 10 THEN
       value := Backup_DiagPartsPara[idx];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, idx, 10);
   value := Backup_DiagPartsPara[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF idx >= ARRAY_MIN AND idx <= ARRAY_MAX THEN
       value := Backup_DiagPartsPara[idx];
   END_IF

예시:

❌ 위험: value := Backup_DiagPartsPara[idx]; // 범위 검사 없음!

✅ 안전: IF idx >= 1 AND idx <= 10 THEN
value := Backup_DiagPartsPara[idx];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: AX_G_LIFE_Alarm_Limit[idx]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF idx >= 1 AND
      idx <= 10 THEN
       value := AX_G_LIFE_Alarm_Limit[idx];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, idx, 10);
   value := AX_G_LIFE_Alarm_Limit[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF idx >= ARRAY_MIN AND idx <= ARRAY_MAX THEN
       value := AX_G_LIFE_Alarm_Limit[idx];
   END_IF

예시:

❌ 위험: value := AX_G_LIFE_Alarm_Limit[idx]; // 범위 검사 없음!

✅ 안전: IF idx >= 1 AND idx <= 10 THEN
value := AX_G_LIFE_Alarm_Limit[idx];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarm[10018 + ( idx - 1)*20]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 10018 + ( idx - 1)*20 >= 1 AND
      10018 + ( idx - 1)*20 <= 10 THEN
       value := fbAlarm[10018 + ( idx - 1)*20];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 10018 + ( idx - 1)*20, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 10018 + ( idx - 1)*20 >= ARRAY_MIN AND 10018 + ( idx - 1)*20 <= ARRAY_MAX THEN
       value := fbAlarm[10018 + ( idx - 1)*20];
   END_IF

예시:

❌ 위험: value := fbAlarm[10018 + ( idx - 1)*20]; // 범위 검사 없음!

✅ 안전: IF 10018 + ( idx - 1)*20 >= 1 AND 10018 + ( idx - 1)*20 <= 10 THEN
value := fbAlarm[10018 + ( idx - 1)*20];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: fbAlarm[10018 + ( idx - 1)*20]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 10018 + ( idx - 1)*20 >= 1 AND
      10018 + ( idx - 1)*20 <= 10 THEN
       value := fbAlarm[10018 + ( idx - 1)*20];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 10018 + ( idx - 1)*20, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 10018 + ( idx - 1)*20 >= ARRAY_MIN AND 10018 + ( idx - 1)*20 <= ARRAY_MAX THEN
       value := fbAlarm[10018 + ( idx - 1)*20];
   END_IF

예시:

❌ 위험: value := fbAlarm[10018 + ( idx - 1)*20]; // 범위 검사 없음!

✅ 안전: IF 10018 + ( idx - 1)*20 >= 1 AND 10018 + ( idx - 1)*20 <= 10 THEN
value := fbAlarm[10018 + ( idx - 1)*20];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX0 <> NULL THEN
       value := QX0^;
       // 또는 QX0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX0) THEN
       value := QX0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX0 := ADR(targetVariable);
   IF QX0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX0^; // NULL 체크 없음!
value := QX0.member; // NULL 체크 없음!

✅ 안전: IF QX0 <> NULL THEN
value := QX0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX0) THEN
value := QX0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3000: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3000 <> NULL THEN
       value := MX3000^;
       // 또는 MX3000.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3000');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3000) THEN
       value := MX3000.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3000 := ADR(targetVariable);
   IF MX3000 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3000 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3000^; // NULL 체크 없음!
value := MX3000.member; // NULL 체크 없음!

✅ 안전: IF MX3000 <> NULL THEN
value := MX3000^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3000) THEN
value := MX3000.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX0 <> NULL THEN
       value := QX0^;
       // 또는 QX0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX0) THEN
       value := QX0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX0 := ADR(targetVariable);
   IF QX0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX0^; // NULL 체크 없음!
value := QX0.member; // NULL 체크 없음!

✅ 안전: IF QX0 <> NULL THEN
value := QX0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX0) THEN
value := QX0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3000: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3000 <> NULL THEN
       value := MX3000^;
       // 또는 MX3000.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3000');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3000) THEN
       value := MX3000.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3000 := ADR(targetVariable);
   IF MX3000 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3000 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3000^; // NULL 체크 없음!
value := MX3000.member; // NULL 체크 없음!

✅ 안전: IF MX3000 <> NULL THEN
value := MX3000^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3000) THEN
value := MX3000.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX0 <> NULL THEN
       value := QX0^;
       // 또는 QX0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX0) THEN
       value := QX0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX0 := ADR(targetVariable);
   IF QX0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX0^; // NULL 체크 없음!
value := QX0.member; // NULL 체크 없음!

✅ 안전: IF QX0 <> NULL THEN
value := QX0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX0) THEN
value := QX0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3000: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3000 <> NULL THEN
       value := MX3000^;
       // 또는 MX3000.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3000');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3000) THEN
       value := MX3000.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3000 := ADR(targetVariable);
   IF MX3000 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3000 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3000^; // NULL 체크 없음!
value := MX3000.member; // NULL 체크 없음!

✅ 안전: IF MX3000 <> NULL THEN
value := MX3000^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3000) THEN
value := MX3000.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX0 <> NULL THEN
       value := QX0^;
       // 또는 QX0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX0) THEN
       value := QX0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX0 := ADR(targetVariable);
   IF QX0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX0^; // NULL 체크 없음!
value := QX0.member; // NULL 체크 없음!

✅ 안전: IF QX0 <> NULL THEN
value := QX0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX0) THEN
value := QX0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3000: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3000 <> NULL THEN
       value := MX3000^;
       // 또는 MX3000.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3000');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3000) THEN
       value := MX3000.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3000 := ADR(targetVariable);
   IF MX3000 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3000 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3000^; // NULL 체크 없음!
value := MX3000.member; // NULL 체크 없음!

✅ 안전: IF MX3000 <> NULL THEN
value := MX3000^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3000) THEN
value := MX3000.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX1: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX1 <> NULL THEN
       value := QX1^;
       // 또는 QX1.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX1');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX1) THEN
       value := QX1.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX1 := ADR(targetVariable);
   IF QX1 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX1 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX1^; // NULL 체크 없음!
value := QX1.member; // NULL 체크 없음!

✅ 안전: IF QX1 <> NULL THEN
value := QX1^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX1) THEN
value := QX1.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3001: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3001 <> NULL THEN
       value := MX3001^;
       // 또는 MX3001.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3001');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3001) THEN
       value := MX3001.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3001 := ADR(targetVariable);
   IF MX3001 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3001 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3001^; // NULL 체크 없음!
value := MX3001.member; // NULL 체크 없음!

✅ 안전: IF MX3001 <> NULL THEN
value := MX3001^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3001) THEN
value := MX3001.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX1: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX1 <> NULL THEN
       value := QX1^;
       // 또는 QX1.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX1');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX1) THEN
       value := QX1.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX1 := ADR(targetVariable);
   IF QX1 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX1 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX1^; // NULL 체크 없음!
value := QX1.member; // NULL 체크 없음!

✅ 안전: IF QX1 <> NULL THEN
value := QX1^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX1) THEN
value := QX1.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3001: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3001 <> NULL THEN
       value := MX3001^;
       // 또는 MX3001.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3001');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3001) THEN
       value := MX3001.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3001 := ADR(targetVariable);
   IF MX3001 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3001 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3001^; // NULL 체크 없음!
value := MX3001.member; // NULL 체크 없음!

✅ 안전: IF MX3001 <> NULL THEN
value := MX3001^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3001) THEN
value := MX3001.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX1: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX1 <> NULL THEN
       value := QX1^;
       // 또는 QX1.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX1');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX1) THEN
       value := QX1.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX1 := ADR(targetVariable);
   IF QX1 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX1 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX1^; // NULL 체크 없음!
value := QX1.member; // NULL 체크 없음!

✅ 안전: IF QX1 <> NULL THEN
value := QX1^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX1) THEN
value := QX1.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3001: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3001 <> NULL THEN
       value := MX3001^;
       // 또는 MX3001.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3001');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3001) THEN
       value := MX3001.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3001 := ADR(targetVariable);
   IF MX3001 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3001 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3001^; // NULL 체크 없음!
value := MX3001.member; // NULL 체크 없음!

✅ 안전: IF MX3001 <> NULL THEN
value := MX3001^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3001) THEN
value := MX3001.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX1: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX1 <> NULL THEN
       value := QX1^;
       // 또는 QX1.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX1');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX1) THEN
       value := QX1.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX1 := ADR(targetVariable);
   IF QX1 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX1 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX1^; // NULL 체크 없음!
value := QX1.member; // NULL 체크 없음!

✅ 안전: IF QX1 <> NULL THEN
value := QX1^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX1) THEN
value := QX1.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3001: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3001 <> NULL THEN
       value := MX3001^;
       // 또는 MX3001.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3001');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3001) THEN
       value := MX3001.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3001 := ADR(targetVariable);
   IF MX3001 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3001 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3001^; // NULL 체크 없음!
value := MX3001.member; // NULL 체크 없음!

✅ 안전: IF MX3001 <> NULL THEN
value := MX3001^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3001) THEN
value := MX3001.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX13: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX13 <> NULL THEN
       value := QX13^;
       // 또는 QX13.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX13');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX13) THEN
       value := QX13.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX13 := ADR(targetVariable);
   IF QX13 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX13 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX13^; // NULL 체크 없음!
value := QX13.member; // NULL 체크 없음!

✅ 안전: IF QX13 <> NULL THEN
value := QX13^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX13) THEN
value := QX13.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3013: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3013 <> NULL THEN
       value := MX3013^;
       // 또는 MX3013.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3013');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3013) THEN
       value := MX3013.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3013 := ADR(targetVariable);
   IF MX3013 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3013 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3013^; // NULL 체크 없음!
value := MX3013.member; // NULL 체크 없음!

✅ 안전: IF MX3013 <> NULL THEN
value := MX3013^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3013) THEN
value := MX3013.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX13: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX13 <> NULL THEN
       value := QX13^;
       // 또는 QX13.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX13');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX13) THEN
       value := QX13.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX13 := ADR(targetVariable);
   IF QX13 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX13 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX13^; // NULL 체크 없음!
value := QX13.member; // NULL 체크 없음!

✅ 안전: IF QX13 <> NULL THEN
value := QX13^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX13) THEN
value := QX13.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3013: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3013 <> NULL THEN
       value := MX3013^;
       // 또는 MX3013.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3013');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3013) THEN
       value := MX3013.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3013 := ADR(targetVariable);
   IF MX3013 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3013 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3013^; // NULL 체크 없음!
value := MX3013.member; // NULL 체크 없음!

✅ 안전: IF MX3013 <> NULL THEN
value := MX3013^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3013) THEN
value := MX3013.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX13: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX13 <> NULL THEN
       value := QX13^;
       // 또는 QX13.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX13');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX13) THEN
       value := QX13.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX13 := ADR(targetVariable);
   IF QX13 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX13 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX13^; // NULL 체크 없음!
value := QX13.member; // NULL 체크 없음!

✅ 안전: IF QX13 <> NULL THEN
value := QX13^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX13) THEN
value := QX13.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3013: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3013 <> NULL THEN
       value := MX3013^;
       // 또는 MX3013.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3013');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3013) THEN
       value := MX3013.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3013 := ADR(targetVariable);
   IF MX3013 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3013 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3013^; // NULL 체크 없음!
value := MX3013.member; // NULL 체크 없음!

✅ 안전: IF MX3013 <> NULL THEN
value := MX3013^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3013) THEN
value := MX3013.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX13: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX13 <> NULL THEN
       value := QX13^;
       // 또는 QX13.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX13');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX13) THEN
       value := QX13.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX13 := ADR(targetVariable);
   IF QX13 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX13 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX13^; // NULL 체크 없음!
value := QX13.member; // NULL 체크 없음!

✅ 안전: IF QX13 <> NULL THEN
value := QX13^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX13) THEN
value := QX13.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3013: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3013 <> NULL THEN
       value := MX3013^;
       // 또는 MX3013.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3013');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3013) THEN
       value := MX3013.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3013 := ADR(targetVariable);
   IF MX3013 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3013 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3013^; // NULL 체크 없음!
value := MX3013.member; // NULL 체크 없음!

✅ 안전: IF MX3013 <> NULL THEN
value := MX3013^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3013) THEN
value := MX3013.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX14: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX14 <> NULL THEN
       value := QX14^;
       // 또는 QX14.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX14');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX14) THEN
       value := QX14.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX14 := ADR(targetVariable);
   IF QX14 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX14 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX14^; // NULL 체크 없음!
value := QX14.member; // NULL 체크 없음!

✅ 안전: IF QX14 <> NULL THEN
value := QX14^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX14) THEN
value := QX14.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3014: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3014 <> NULL THEN
       value := MX3014^;
       // 또는 MX3014.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3014');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3014) THEN
       value := MX3014.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3014 := ADR(targetVariable);
   IF MX3014 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3014 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3014^; // NULL 체크 없음!
value := MX3014.member; // NULL 체크 없음!

✅ 안전: IF MX3014 <> NULL THEN
value := MX3014^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3014) THEN
value := MX3014.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX14: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX14 <> NULL THEN
       value := QX14^;
       // 또는 QX14.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX14');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX14) THEN
       value := QX14.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX14 := ADR(targetVariable);
   IF QX14 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX14 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX14^; // NULL 체크 없음!
value := QX14.member; // NULL 체크 없음!

✅ 안전: IF QX14 <> NULL THEN
value := QX14^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX14) THEN
value := QX14.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3014: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3014 <> NULL THEN
       value := MX3014^;
       // 또는 MX3014.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3014');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3014) THEN
       value := MX3014.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3014 := ADR(targetVariable);
   IF MX3014 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3014 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3014^; // NULL 체크 없음!
value := MX3014.member; // NULL 체크 없음!

✅ 안전: IF MX3014 <> NULL THEN
value := MX3014^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3014) THEN
value := MX3014.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX14: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX14 <> NULL THEN
       value := QX14^;
       // 또는 QX14.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX14');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX14) THEN
       value := QX14.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX14 := ADR(targetVariable);
   IF QX14 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX14 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX14^; // NULL 체크 없음!
value := QX14.member; // NULL 체크 없음!

✅ 안전: IF QX14 <> NULL THEN
value := QX14^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX14) THEN
value := QX14.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3014: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3014 <> NULL THEN
       value := MX3014^;
       // 또는 MX3014.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3014');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3014) THEN
       value := MX3014.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3014 := ADR(targetVariable);
   IF MX3014 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3014 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3014^; // NULL 체크 없음!
value := MX3014.member; // NULL 체크 없음!

✅ 안전: IF MX3014 <> NULL THEN
value := MX3014^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3014) THEN
value := MX3014.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX14: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX14 <> NULL THEN
       value := QX14^;
       // 또는 QX14.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX14');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX14) THEN
       value := QX14.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX14 := ADR(targetVariable);
   IF QX14 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX14 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX14^; // NULL 체크 없음!
value := QX14.member; // NULL 체크 없음!

✅ 안전: IF QX14 <> NULL THEN
value := QX14^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX14) THEN
value := QX14.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3014: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3014 <> NULL THEN
       value := MX3014^;
       // 또는 MX3014.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3014');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3014) THEN
       value := MX3014.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3014 := ADR(targetVariable);
   IF MX3014 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3014 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3014^; // NULL 체크 없음!
value := MX3014.member; // NULL 체크 없음!

✅ 안전: IF MX3014 <> NULL THEN
value := MX3014^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3014) THEN
value := MX3014.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX14: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX14 <> NULL THEN
       value := QX14^;
       // 또는 QX14.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX14');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX14) THEN
       value := QX14.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX14 := ADR(targetVariable);
   IF QX14 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX14 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX14^; // NULL 체크 없음!
value := QX14.member; // NULL 체크 없음!

✅ 안전: IF QX14 <> NULL THEN
value := QX14^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX14) THEN
value := QX14.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3014: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3014 <> NULL THEN
       value := MX3014^;
       // 또는 MX3014.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3014');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3014) THEN
       value := MX3014.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3014 := ADR(targetVariable);
   IF MX3014 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3014 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3014^; // NULL 체크 없음!
value := MX3014.member; // NULL 체크 없음!

✅ 안전: IF MX3014 <> NULL THEN
value := MX3014^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3014) THEN
value := MX3014.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX14: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX14 <> NULL THEN
       value := QX14^;
       // 또는 QX14.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX14');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX14) THEN
       value := QX14.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX14 := ADR(targetVariable);
   IF QX14 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX14 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX14^; // NULL 체크 없음!
value := QX14.member; // NULL 체크 없음!

✅ 안전: IF QX14 <> NULL THEN
value := QX14^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX14) THEN
value := QX14.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3014: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3014 <> NULL THEN
       value := MX3014^;
       // 또는 MX3014.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3014');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3014) THEN
       value := MX3014.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3014 := ADR(targetVariable);
   IF MX3014 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3014 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3014^; // NULL 체크 없음!
value := MX3014.member; // NULL 체크 없음!

✅ 안전: IF MX3014 <> NULL THEN
value := MX3014^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3014) THEN
value := MX3014.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX14: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX14 <> NULL THEN
       value := QX14^;
       // 또는 QX14.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX14');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX14) THEN
       value := QX14.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX14 := ADR(targetVariable);
   IF QX14 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX14 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX14^; // NULL 체크 없음!
value := QX14.member; // NULL 체크 없음!

✅ 안전: IF QX14 <> NULL THEN
value := QX14^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX14) THEN
value := QX14.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3014: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3014 <> NULL THEN
       value := MX3014^;
       // 또는 MX3014.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3014');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3014) THEN
       value := MX3014.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3014 := ADR(targetVariable);
   IF MX3014 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3014 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3014^; // NULL 체크 없음!
value := MX3014.member; // NULL 체크 없음!

✅ 안전: IF MX3014 <> NULL THEN
value := MX3014^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3014) THEN
value := MX3014.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX14: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX14 <> NULL THEN
       value := QX14^;
       // 또는 QX14.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX14');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX14) THEN
       value := QX14.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX14 := ADR(targetVariable);
   IF QX14 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX14 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX14^; // NULL 체크 없음!
value := QX14.member; // NULL 체크 없음!

✅ 안전: IF QX14 <> NULL THEN
value := QX14^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX14) THEN
value := QX14.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3014: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3014 <> NULL THEN
       value := MX3014^;
       // 또는 MX3014.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3014');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3014) THEN
       value := MX3014.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3014 := ADR(targetVariable);
   IF MX3014 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3014 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3014^; // NULL 체크 없음!
value := MX3014.member; // NULL 체크 없음!

✅ 안전: IF MX3014 <> NULL THEN
value := MX3014^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3014) THEN
value := MX3014.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX16: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX16 <> NULL THEN
       value := QX16^;
       // 또는 QX16.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX16');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX16) THEN
       value := QX16.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX16 := ADR(targetVariable);
   IF QX16 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX16 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX16^; // NULL 체크 없음!
value := QX16.member; // NULL 체크 없음!

✅ 안전: IF QX16 <> NULL THEN
value := QX16^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX16) THEN
value := QX16.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3016: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3016 <> NULL THEN
       value := MX3016^;
       // 또는 MX3016.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3016');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3016) THEN
       value := MX3016.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3016 := ADR(targetVariable);
   IF MX3016 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3016 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3016^; // NULL 체크 없음!
value := MX3016.member; // NULL 체크 없음!

✅ 안전: IF MX3016 <> NULL THEN
value := MX3016^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3016) THEN
value := MX3016.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX16: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX16 <> NULL THEN
       value := QX16^;
       // 또는 QX16.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX16');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX16) THEN
       value := QX16.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX16 := ADR(targetVariable);
   IF QX16 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX16 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX16^; // NULL 체크 없음!
value := QX16.member; // NULL 체크 없음!

✅ 안전: IF QX16 <> NULL THEN
value := QX16^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX16) THEN
value := QX16.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3016: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3016 <> NULL THEN
       value := MX3016^;
       // 또는 MX3016.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3016');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3016) THEN
       value := MX3016.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3016 := ADR(targetVariable);
   IF MX3016 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3016 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3016^; // NULL 체크 없음!
value := MX3016.member; // NULL 체크 없음!

✅ 안전: IF MX3016 <> NULL THEN
value := MX3016^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3016) THEN
value := MX3016.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX16: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX16 <> NULL THEN
       value := QX16^;
       // 또는 QX16.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX16');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX16) THEN
       value := QX16.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX16 := ADR(targetVariable);
   IF QX16 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX16 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX16^; // NULL 체크 없음!
value := QX16.member; // NULL 체크 없음!

✅ 안전: IF QX16 <> NULL THEN
value := QX16^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX16) THEN
value := QX16.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3016: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3016 <> NULL THEN
       value := MX3016^;
       // 또는 MX3016.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3016');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3016) THEN
       value := MX3016.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3016 := ADR(targetVariable);
   IF MX3016 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3016 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3016^; // NULL 체크 없음!
value := MX3016.member; // NULL 체크 없음!

✅ 안전: IF MX3016 <> NULL THEN
value := MX3016^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3016) THEN
value := MX3016.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX16: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX16 <> NULL THEN
       value := QX16^;
       // 또는 QX16.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX16');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX16) THEN
       value := QX16.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX16 := ADR(targetVariable);
   IF QX16 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX16 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX16^; // NULL 체크 없음!
value := QX16.member; // NULL 체크 없음!

✅ 안전: IF QX16 <> NULL THEN
value := QX16^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX16) THEN
value := QX16.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3016: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3016 <> NULL THEN
       value := MX3016^;
       // 또는 MX3016.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3016');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3016) THEN
       value := MX3016.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3016 := ADR(targetVariable);
   IF MX3016 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3016 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3016^; // NULL 체크 없음!
value := MX3016.member; // NULL 체크 없음!

✅ 안전: IF MX3016 <> NULL THEN
value := MX3016^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3016) THEN
value := MX3016.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX18: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX18 <> NULL THEN
       value := QX18^;
       // 또는 QX18.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX18');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX18) THEN
       value := QX18.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX18 := ADR(targetVariable);
   IF QX18 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX18 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX18^; // NULL 체크 없음!
value := QX18.member; // NULL 체크 없음!

✅ 안전: IF QX18 <> NULL THEN
value := QX18^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX18) THEN
value := QX18.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3018: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3018 <> NULL THEN
       value := MX3018^;
       // 또는 MX3018.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3018');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3018) THEN
       value := MX3018.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3018 := ADR(targetVariable);
   IF MX3018 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3018 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3018^; // NULL 체크 없음!
value := MX3018.member; // NULL 체크 없음!

✅ 안전: IF MX3018 <> NULL THEN
value := MX3018^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3018) THEN
value := MX3018.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX18: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX18 <> NULL THEN
       value := QX18^;
       // 또는 QX18.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX18');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX18) THEN
       value := QX18.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX18 := ADR(targetVariable);
   IF QX18 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX18 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX18^; // NULL 체크 없음!
value := QX18.member; // NULL 체크 없음!

✅ 안전: IF QX18 <> NULL THEN
value := QX18^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX18) THEN
value := QX18.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3018: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3018 <> NULL THEN
       value := MX3018^;
       // 또는 MX3018.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3018');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3018) THEN
       value := MX3018.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3018 := ADR(targetVariable);
   IF MX3018 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3018 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3018^; // NULL 체크 없음!
value := MX3018.member; // NULL 체크 없음!

✅ 안전: IF MX3018 <> NULL THEN
value := MX3018^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3018) THEN
value := MX3018.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX18: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX18 <> NULL THEN
       value := QX18^;
       // 또는 QX18.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX18');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX18) THEN
       value := QX18.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX18 := ADR(targetVariable);
   IF QX18 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX18 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX18^; // NULL 체크 없음!
value := QX18.member; // NULL 체크 없음!

✅ 안전: IF QX18 <> NULL THEN
value := QX18^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX18) THEN
value := QX18.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3018: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3018 <> NULL THEN
       value := MX3018^;
       // 또는 MX3018.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3018');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3018) THEN
       value := MX3018.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3018 := ADR(targetVariable);
   IF MX3018 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3018 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3018^; // NULL 체크 없음!
value := MX3018.member; // NULL 체크 없음!

✅ 안전: IF MX3018 <> NULL THEN
value := MX3018^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3018) THEN
value := MX3018.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX23: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX23 <> NULL THEN
       value := QX23^;
       // 또는 QX23.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX23');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX23) THEN
       value := QX23.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX23 := ADR(targetVariable);
   IF QX23 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX23 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX23^; // NULL 체크 없음!
value := QX23.member; // NULL 체크 없음!

✅ 안전: IF QX23 <> NULL THEN
value := QX23^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX23) THEN
value := QX23.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3023: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3023 <> NULL THEN
       value := MX3023^;
       // 또는 MX3023.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3023');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3023) THEN
       value := MX3023.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3023 := ADR(targetVariable);
   IF MX3023 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3023 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3023^; // NULL 체크 없음!
value := MX3023.member; // NULL 체크 없음!

✅ 안전: IF MX3023 <> NULL THEN
value := MX3023^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3023) THEN
value := MX3023.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: QX25: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF QX25 <> NULL THEN
       value := QX25^;
       // 또는 QX25.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: QX25');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(QX25) THEN
       value := QX25.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   QX25 := ADR(targetVariable);
   IF QX25 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF QX25 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := QX25^; // NULL 체크 없음!
value := QX25.member; // NULL 체크 없음!

✅ 안전: IF QX25 <> NULL THEN
value := QX25^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(QX25) THEN
value := QX25.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: MX3025: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MX3025 <> NULL THEN
       value := MX3025^;
       // 또는 MX3025.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MX3025');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MX3025) THEN
       value := MX3025.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MX3025 := ADR(targetVariable);
   IF MX3025 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MX3025 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MX3025^; // NULL 체크 없음!
value := MX3025.member; // NULL 체크 없음!

✅ 안전: IF MX3025 <> NULL THEN
value := MX3025^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MX3025) THEN
value := MX3025.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: SYS_TrendData: 995줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SYS_TrendData = 995줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: Boot = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Boot - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Boot >= (FALSE - 1.0E-6) AND
      Boot <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Boot >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Boot * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Boot = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Boot - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: ARRAY[1..cMAX_Log_Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Log_Item >= 1 AND
      1..cMAX_Log_Item <= 10 THEN
       value := ARRAY[1..cMAX_Log_Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Log_Item, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Log_Item >= ARRAY_MIN AND 1..cMAX_Log_Item <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Log_Item];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Log_Item]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Log_Item >= 1 AND 1..cMAX_Log_Item <= 10 THEN
value := ARRAY[1..cMAX_Log_Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: ARRAY[1..cMAX_Log_Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Log_Item >= 1 AND
      1..cMAX_Log_Item <= 10 THEN
       value := ARRAY[1..cMAX_Log_Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Log_Item, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Log_Item >= ARRAY_MIN AND 1..cMAX_Log_Item <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Log_Item];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Log_Item]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Log_Item >= 1 AND 1..cMAX_Log_Item <= 10 THEN
value := ARRAY[1..cMAX_Log_Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AI_MFC_FLOW[cMFC01_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC01_Index >= 1 AND
      cMFC01_Index <= 10 THEN
       value := AI_MFC_FLOW[cMFC01_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC01_Index, 10);
   value := AI_MFC_FLOW[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC01_Index >= ARRAY_MIN AND cMFC01_Index <= ARRAY_MAX THEN
       value := AI_MFC_FLOW[cMFC01_Index];
   END_IF

예시:

❌ 위험: value := AI_MFC_FLOW[cMFC01_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC01_Index >= 1 AND cMFC01_Index <= 10 THEN
value := AI_MFC_FLOW[cMFC01_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AO_MFC_SET[cMFC01_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC01_Index >= 1 AND
      cMFC01_Index <= 10 THEN
       value := AO_MFC_SET[cMFC01_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC01_Index, 10);
   value := AO_MFC_SET[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC01_Index >= ARRAY_MIN AND cMFC01_Index <= ARRAY_MAX THEN
       value := AO_MFC_SET[cMFC01_Index];
   END_IF

예시:

❌ 위험: value := AO_MFC_SET[cMFC01_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC01_Index >= 1 AND cMFC01_Index <= 10 THEN
value := AO_MFC_SET[cMFC01_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AI_MFC_FLOW[cMFC02_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC02_Index >= 1 AND
      cMFC02_Index <= 10 THEN
       value := AI_MFC_FLOW[cMFC02_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC02_Index, 10);
   value := AI_MFC_FLOW[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC02_Index >= ARRAY_MIN AND cMFC02_Index <= ARRAY_MAX THEN
       value := AI_MFC_FLOW[cMFC02_Index];
   END_IF

예시:

❌ 위험: value := AI_MFC_FLOW[cMFC02_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC02_Index >= 1 AND cMFC02_Index <= 10 THEN
value := AI_MFC_FLOW[cMFC02_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AO_MFC_SET[cMFC02_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC02_Index >= 1 AND
      cMFC02_Index <= 10 THEN
       value := AO_MFC_SET[cMFC02_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC02_Index, 10);
   value := AO_MFC_SET[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC02_Index >= ARRAY_MIN AND cMFC02_Index <= ARRAY_MAX THEN
       value := AO_MFC_SET[cMFC02_Index];
   END_IF

예시:

❌ 위험: value := AO_MFC_SET[cMFC02_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC02_Index >= 1 AND cMFC02_Index <= 10 THEN
value := AO_MFC_SET[cMFC02_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AI_MFC_FLOW[cMFC03_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC03_Index >= 1 AND
      cMFC03_Index <= 10 THEN
       value := AI_MFC_FLOW[cMFC03_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC03_Index, 10);
   value := AI_MFC_FLOW[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC03_Index >= ARRAY_MIN AND cMFC03_Index <= ARRAY_MAX THEN
       value := AI_MFC_FLOW[cMFC03_Index];
   END_IF

예시:

❌ 위험: value := AI_MFC_FLOW[cMFC03_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC03_Index >= 1 AND cMFC03_Index <= 10 THEN
value := AI_MFC_FLOW[cMFC03_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AO_MFC_SET[cMFC03_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC03_Index >= 1 AND
      cMFC03_Index <= 10 THEN
       value := AO_MFC_SET[cMFC03_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC03_Index, 10);
   value := AO_MFC_SET[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC03_Index >= ARRAY_MIN AND cMFC03_Index <= ARRAY_MAX THEN
       value := AO_MFC_SET[cMFC03_Index];
   END_IF

예시:

❌ 위험: value := AO_MFC_SET[cMFC03_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC03_Index >= 1 AND cMFC03_Index <= 10 THEN
value := AO_MFC_SET[cMFC03_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AI_MFC_FLOW[cMFC04_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC04_Index >= 1 AND
      cMFC04_Index <= 10 THEN
       value := AI_MFC_FLOW[cMFC04_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC04_Index, 10);
   value := AI_MFC_FLOW[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC04_Index >= ARRAY_MIN AND cMFC04_Index <= ARRAY_MAX THEN
       value := AI_MFC_FLOW[cMFC04_Index];
   END_IF

예시:

❌ 위험: value := AI_MFC_FLOW[cMFC04_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC04_Index >= 1 AND cMFC04_Index <= 10 THEN
value := AI_MFC_FLOW[cMFC04_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AO_MFC_SET[cMFC04_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC04_Index >= 1 AND
      cMFC04_Index <= 10 THEN
       value := AO_MFC_SET[cMFC04_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC04_Index, 10);
   value := AO_MFC_SET[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC04_Index >= ARRAY_MIN AND cMFC04_Index <= ARRAY_MAX THEN
       value := AO_MFC_SET[cMFC04_Index];
   END_IF

예시:

❌ 위험: value := AO_MFC_SET[cMFC04_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC04_Index >= 1 AND cMFC04_Index <= 10 THEN
value := AO_MFC_SET[cMFC04_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AI_MFC_FLOW[cMFC05_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC05_Index >= 1 AND
      cMFC05_Index <= 10 THEN
       value := AI_MFC_FLOW[cMFC05_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC05_Index, 10);
   value := AI_MFC_FLOW[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC05_Index >= ARRAY_MIN AND cMFC05_Index <= ARRAY_MAX THEN
       value := AI_MFC_FLOW[cMFC05_Index];
   END_IF

예시:

❌ 위험: value := AI_MFC_FLOW[cMFC05_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC05_Index >= 1 AND cMFC05_Index <= 10 THEN
value := AI_MFC_FLOW[cMFC05_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AO_MFC_SET[cMFC05_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC05_Index >= 1 AND
      cMFC05_Index <= 10 THEN
       value := AO_MFC_SET[cMFC05_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC05_Index, 10);
   value := AO_MFC_SET[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC05_Index >= ARRAY_MIN AND cMFC05_Index <= ARRAY_MAX THEN
       value := AO_MFC_SET[cMFC05_Index];
   END_IF

예시:

❌ 위험: value := AO_MFC_SET[cMFC05_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC05_Index >= 1 AND cMFC05_Index <= 10 THEN
value := AO_MFC_SET[cMFC05_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AI_MFC_FLOW[cMFC06_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC06_Index >= 1 AND
      cMFC06_Index <= 10 THEN
       value := AI_MFC_FLOW[cMFC06_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC06_Index, 10);
   value := AI_MFC_FLOW[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC06_Index >= ARRAY_MIN AND cMFC06_Index <= ARRAY_MAX THEN
       value := AI_MFC_FLOW[cMFC06_Index];
   END_IF

예시:

❌ 위험: value := AI_MFC_FLOW[cMFC06_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC06_Index >= 1 AND cMFC06_Index <= 10 THEN
value := AI_MFC_FLOW[cMFC06_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AO_MFC_SET[cMFC06_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC06_Index >= 1 AND
      cMFC06_Index <= 10 THEN
       value := AO_MFC_SET[cMFC06_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC06_Index, 10);
   value := AO_MFC_SET[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC06_Index >= ARRAY_MIN AND cMFC06_Index <= ARRAY_MAX THEN
       value := AO_MFC_SET[cMFC06_Index];
   END_IF

예시:

❌ 위험: value := AO_MFC_SET[cMFC06_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC06_Index >= 1 AND cMFC06_Index <= 10 THEN
value := AO_MFC_SET[cMFC06_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AI_MFC_FLOW[cMFC07_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC07_Index >= 1 AND
      cMFC07_Index <= 10 THEN
       value := AI_MFC_FLOW[cMFC07_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC07_Index, 10);
   value := AI_MFC_FLOW[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC07_Index >= ARRAY_MIN AND cMFC07_Index <= ARRAY_MAX THEN
       value := AI_MFC_FLOW[cMFC07_Index];
   END_IF

예시:

❌ 위험: value := AI_MFC_FLOW[cMFC07_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC07_Index >= 1 AND cMFC07_Index <= 10 THEN
value := AI_MFC_FLOW[cMFC07_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AO_MFC_SET[cMFC07_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC07_Index >= 1 AND
      cMFC07_Index <= 10 THEN
       value := AO_MFC_SET[cMFC07_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC07_Index, 10);
   value := AO_MFC_SET[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC07_Index >= ARRAY_MIN AND cMFC07_Index <= ARRAY_MAX THEN
       value := AO_MFC_SET[cMFC07_Index];
   END_IF

예시:

❌ 위험: value := AO_MFC_SET[cMFC07_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC07_Index >= 1 AND cMFC07_Index <= 10 THEN
value := AO_MFC_SET[cMFC07_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AI_MFC_FLOW[cMFC08_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC08_Index >= 1 AND
      cMFC08_Index <= 10 THEN
       value := AI_MFC_FLOW[cMFC08_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC08_Index, 10);
   value := AI_MFC_FLOW[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC08_Index >= ARRAY_MIN AND cMFC08_Index <= ARRAY_MAX THEN
       value := AI_MFC_FLOW[cMFC08_Index];
   END_IF

예시:

❌ 위험: value := AI_MFC_FLOW[cMFC08_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC08_Index >= 1 AND cMFC08_Index <= 10 THEN
value := AI_MFC_FLOW[cMFC08_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AO_MFC_SET[cMFC08_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC08_Index >= 1 AND
      cMFC08_Index <= 10 THEN
       value := AO_MFC_SET[cMFC08_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC08_Index, 10);
   value := AO_MFC_SET[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC08_Index >= ARRAY_MIN AND cMFC08_Index <= ARRAY_MAX THEN
       value := AO_MFC_SET[cMFC08_Index];
   END_IF

예시:

❌ 위험: value := AO_MFC_SET[cMFC08_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC08_Index >= 1 AND cMFC08_Index <= 10 THEN
value := AO_MFC_SET[cMFC08_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AI_MFC_FLOW[cMFC09_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC09_Index >= 1 AND
      cMFC09_Index <= 10 THEN
       value := AI_MFC_FLOW[cMFC09_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC09_Index, 10);
   value := AI_MFC_FLOW[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC09_Index >= ARRAY_MIN AND cMFC09_Index <= ARRAY_MAX THEN
       value := AI_MFC_FLOW[cMFC09_Index];
   END_IF

예시:

❌ 위험: value := AI_MFC_FLOW[cMFC09_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC09_Index >= 1 AND cMFC09_Index <= 10 THEN
value := AI_MFC_FLOW[cMFC09_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AO_MFC_SET[cMFC09_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC09_Index >= 1 AND
      cMFC09_Index <= 10 THEN
       value := AO_MFC_SET[cMFC09_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC09_Index, 10);
   value := AO_MFC_SET[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC09_Index >= ARRAY_MIN AND cMFC09_Index <= ARRAY_MAX THEN
       value := AO_MFC_SET[cMFC09_Index];
   END_IF

예시:

❌ 위험: value := AO_MFC_SET[cMFC09_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC09_Index >= 1 AND cMFC09_Index <= 10 THEN
value := AO_MFC_SET[cMFC09_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AI_MFC_FLOW[cMFC100_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC100_Index >= 1 AND
      cMFC100_Index <= 10 THEN
       value := AI_MFC_FLOW[cMFC100_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC100_Index, 10);
   value := AI_MFC_FLOW[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC100_Index >= ARRAY_MIN AND cMFC100_Index <= ARRAY_MAX THEN
       value := AI_MFC_FLOW[cMFC100_Index];
   END_IF

예시:

❌ 위험: value := AI_MFC_FLOW[cMFC100_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC100_Index >= 1 AND cMFC100_Index <= 10 THEN
value := AI_MFC_FLOW[cMFC100_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AO_MFC_SET[cMFC100_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC100_Index >= 1 AND
      cMFC100_Index <= 10 THEN
       value := AO_MFC_SET[cMFC100_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC100_Index, 10);
   value := AO_MFC_SET[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC100_Index >= ARRAY_MIN AND cMFC100_Index <= ARRAY_MAX THEN
       value := AO_MFC_SET[cMFC100_Index];
   END_IF

예시:

❌ 위험: value := AO_MFC_SET[cMFC100_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC100_Index >= 1 AND cMFC100_Index <= 10 THEN
value := AO_MFC_SET[cMFC100_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AI_MFC_FLOW[cMFC101_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC101_Index >= 1 AND
      cMFC101_Index <= 10 THEN
       value := AI_MFC_FLOW[cMFC101_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC101_Index, 10);
   value := AI_MFC_FLOW[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC101_Index >= ARRAY_MIN AND cMFC101_Index <= ARRAY_MAX THEN
       value := AI_MFC_FLOW[cMFC101_Index];
   END_IF

예시:

❌ 위험: value := AI_MFC_FLOW[cMFC101_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC101_Index >= 1 AND cMFC101_Index <= 10 THEN
value := AI_MFC_FLOW[cMFC101_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: AO_MFC_SET[cMFC101_Index]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF cMFC101_Index >= 1 AND
      cMFC101_Index <= 10 THEN
       value := AO_MFC_SET[cMFC101_Index];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, cMFC101_Index, 10);
   value := AO_MFC_SET[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF cMFC101_Index >= ARRAY_MIN AND cMFC101_Index <= ARRAY_MAX THEN
       value := AO_MFC_SET[cMFC101_Index];
   END_IF

예시:

❌ 위험: value := AO_MFC_SET[cMFC101_Index]; // 범위 검사 없음!

✅ 안전: IF cMFC101_Index >= 1 AND cMFC101_Index <= 10 THEN
value := AO_MFC_SET[cMFC101_Index];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: TitleWait_Timer: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF TitleWait_Timer <> NULL THEN
       value := TitleWait_Timer^;
       // 또는 TitleWait_Timer.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: TitleWait_Timer');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(TitleWait_Timer) THEN
       value := TitleWait_Timer.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   TitleWait_Timer := ADR(targetVariable);
   IF TitleWait_Timer = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF TitleWait_Timer = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := TitleWait_Timer^; // NULL 체크 없음!
value := TitleWait_Timer.member; // NULL 체크 없음!

✅ 안전: IF TitleWait_Timer <> NULL THEN
value := TitleWait_Timer^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(TitleWait_Timer) THEN
value := TitleWait_Timer.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: Interval_Timer: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Interval_Timer <> NULL THEN
       value := Interval_Timer^;
       // 또는 Interval_Timer.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Interval_Timer');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Interval_Timer) THEN
       value := Interval_Timer.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Interval_Timer := ADR(targetVariable);
   IF Interval_Timer = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Interval_Timer = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Interval_Timer^; // NULL 체크 없음!
value := Interval_Timer.member; // NULL 체크 없음!

✅ 안전: IF Interval_Timer <> NULL THEN
value := Interval_Timer^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Interval_Timer) THEN
value := Interval_Timer.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: SEQ_Function_Process: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF SEQ_Function_Process <> NULL THEN
       value := SEQ_Function_Process^;
       // 또는 SEQ_Function_Process.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: SEQ_Function_Process');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(SEQ_Function_Process) THEN
       value := SEQ_Function_Process.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   SEQ_Function_Process := ADR(targetVariable);
   IF SEQ_Function_Process = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF SEQ_Function_Process = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := SEQ_Function_Process^; // NULL 체크 없음!
value := SEQ_Function_Process.member; // NULL 체크 없음!

✅ 안전: IF SEQ_Function_Process <> NULL THEN
value := SEQ_Function_Process^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(SEQ_Function_Process) THEN
value := SEQ_Function_Process.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: SYS_TrendLog: 254줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SYS_TrendLog = 254줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: DX_SEQ_Function_Process_Exception <> eException_Abort: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Function_Process_Exception - eException_Abort) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Function_Process_Exception >= (eException_Abort - 1.0E-6) AND
      DX_SEQ_Function_Process_Exception <= (eException_Abort + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Function_Process_Exception >= eException_Abort THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Function_Process_Exception * 10.0);
   intTarget := REAL_TO_DINT(eException_Abort * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Function_Process_Exception = eException_Abort THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Function_Process_Exception - eException_Abort) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: DX_SEQ_Interface_Mode = ePRO_READY: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_SEQ_Interface_Mode - ePRO_READY) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_SEQ_Interface_Mode >= (ePRO_READY - 1.0E-6) AND
      DX_SEQ_Interface_Mode <= (ePRO_READY + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_SEQ_Interface_Mode >= ePRO_READY THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_SEQ_Interface_Mode * 10.0);
   intTarget := REAL_TO_DINT(ePRO_READY * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_SEQ_Interface_Mode = ePRO_READY THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_SEQ_Interface_Mode - ePRO_READY) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: DX_INF_State_Process = eProcess_Ready: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Process - eProcess_Ready) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Process >= (eProcess_Ready - 1.0E-6) AND
      DX_INF_State_Process <= (eProcess_Ready + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Process >= eProcess_Ready THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Process * 10.0);
   intTarget := REAL_TO_DINT(eProcess_Ready * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Process = eProcess_Ready THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Process - eProcess_Ready) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: DX_INF_State_Process = eProcess_Processing: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Process >= (eProcess_Processing - 1.0E-6) AND
      DX_INF_State_Process <= (eProcess_Processing + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Process >= eProcess_Processing THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Process * 10.0);
   intTarget := REAL_TO_DINT(eProcess_Processing * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Process = eProcess_Processing THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: eTune_Start = DO_ManualLog_Command: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(eTune_Start - DO_ManualLog_Command) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF eTune_Start >= (DO_ManualLog_Command - 1.0E-6) AND
      eTune_Start <= (DO_ManualLog_Command + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF eTune_Start >= DO_ManualLog_Command THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(eTune_Start * 10.0);
   intTarget := REAL_TO_DINT(DO_ManualLog_Command * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF eTune_Start = DO_ManualLog_Command THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(eTune_Start - DO_ManualLog_Command) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: ProcessLog_Interval = 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(ProcessLog_Interval - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF ProcessLog_Interval >= (0 - 1.0E-6) AND
      ProcessLog_Interval <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF ProcessLog_Interval >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(ProcessLog_Interval * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF ProcessLog_Interval = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(ProcessLog_Interval - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: FALSE = bTitle: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(FALSE - bTitle) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF FALSE >= (bTitle - 1.0E-6) AND
      FALSE <= (bTitle + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF FALSE >= bTitle THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(FALSE * 10.0);
   intTarget := REAL_TO_DINT(bTitle * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF FALSE = bTitle THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(FALSE - bTitle) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: FALSE = TitleWait_Timer.Q: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(FALSE - TitleWait_Timer.Q) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF FALSE >= (TitleWait_Timer.Q - 1.0E-6) AND
      FALSE <= (TitleWait_Timer.Q + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF FALSE >= TitleWait_Timer.Q THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(FALSE * 10.0);
   intTarget := REAL_TO_DINT(TitleWait_Timer.Q * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF FALSE = TitleWait_Timer.Q THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(FALSE - TitleWait_Timer.Q) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: FALSE = Interval_Timer.Q: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(FALSE - Interval_Timer.Q) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF FALSE >= (Interval_Timer.Q - 1.0E-6) AND
      FALSE <= (Interval_Timer.Q + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF FALSE >= Interval_Timer.Q THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(FALSE * 10.0);
   intTarget := REAL_TO_DINT(Interval_Timer.Q * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF FALSE = Interval_Timer.Q THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(FALSE - Interval_Timer.Q) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: Pause_State = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Pause_State - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Pause_State >= (TRUE - 1.0E-6) AND
      Pause_State <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Pause_State >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Pause_State * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Pause_State = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Pause_State - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: DX_INF_State_Process = eProcess_Processing: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Process >= (eProcess_Processing - 1.0E-6) AND
      DX_INF_State_Process <= (eProcess_Processing + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Process >= eProcess_Processing THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Process * 10.0);
   intTarget := REAL_TO_DINT(eProcess_Processing * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Process = eProcess_Processing THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: DX_INF_Abort_Run = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_Abort_Run - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_Abort_Run >= (TRUE - 1.0E-6) AND
      DX_INF_Abort_Run <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_Abort_Run >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_Abort_Run * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_Abort_Run = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_Abort_Run - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: DX_INF_State_Process = eProcess_Processing: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Process >= (eProcess_Processing - 1.0E-6) AND
      DX_INF_State_Process <= (eProcess_Processing + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Process >= eProcess_Processing THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Process * 10.0);
   intTarget := REAL_TO_DINT(eProcess_Processing * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Process = eProcess_Processing THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: DX_INF_Sub_Run = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_Sub_Run - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_Sub_Run >= (TRUE - 1.0E-6) AND
      DX_INF_Sub_Run <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_Sub_Run >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_Sub_Run * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_Sub_Run = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_Sub_Run - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: DX_INF_State_Process = eProcess_Processing: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Process >= (eProcess_Processing - 1.0E-6) AND
      DX_INF_State_Process <= (eProcess_Processing + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Process >= eProcess_Processing THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Process * 10.0);
   intTarget := REAL_TO_DINT(eProcess_Processing * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Process = eProcess_Processing THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: DX_INF_Abort_Run = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_Abort_Run - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_Abort_Run >= (FALSE - 1.0E-6) AND
      DX_INF_Abort_Run <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_Abort_Run >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_Abort_Run * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_Abort_Run = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_Abort_Run - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: DX_INF_Sub_Run = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_Sub_Run - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_Sub_Run >= (FALSE - 1.0E-6) AND
      DX_INF_Sub_Run <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_Sub_Run >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_Sub_Run * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_Sub_Run = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_Sub_Run - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: DX_INF_State_Process = eProcess_Ready: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Process - eProcess_Ready) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Process >= (eProcess_Ready - 1.0E-6) AND
      DX_INF_State_Process <= (eProcess_Ready + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Process >= eProcess_Ready THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Process * 10.0);
   intTarget := REAL_TO_DINT(eProcess_Ready * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Process = eProcess_Ready THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Process - eProcess_Ready) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: ARRAY[1..cMAX_Log_Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Log_Item >= 1 AND
      1..cMAX_Log_Item <= 10 THEN
       value := ARRAY[1..cMAX_Log_Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Log_Item, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Log_Item >= ARRAY_MIN AND 1..cMAX_Log_Item <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Log_Item];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Log_Item]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Log_Item >= 1 AND 1..cMAX_Log_Item <= 10 THEN
value := ARRAY[1..cMAX_Log_Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:1

설명: stExternalParaSet: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF stExternalParaSet <> NULL THEN
       value := stExternalParaSet^;
       // 또는 stExternalParaSet.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: stExternalParaSet');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(stExternalParaSet) THEN
       value := stExternalParaSet.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   stExternalParaSet := ADR(targetVariable);
   IF stExternalParaSet = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF stExternalParaSet = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := stExternalParaSet^; // NULL 체크 없음!
value := stExternalParaSet.member; // NULL 체크 없음!

✅ 안전: IF stExternalParaSet <> NULL THEN
value := stExternalParaSet^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(stExternalParaSet) THEN
value := stExternalParaSet.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:1

설명: stExternalParaSet: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF stExternalParaSet <> NULL THEN
       value := stExternalParaSet^;
       // 또는 stExternalParaSet.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: stExternalParaSet');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(stExternalParaSet) THEN
       value := stExternalParaSet.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   stExternalParaSet := ADR(targetVariable);
   IF stExternalParaSet = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF stExternalParaSet = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := stExternalParaSet^; // NULL 체크 없음!
value := stExternalParaSet.member; // NULL 체크 없음!

✅ 안전: IF stExternalParaSet <> NULL THEN
value := stExternalParaSet^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(stExternalParaSet) THEN
value := stExternalParaSet.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:1

설명: stExternalParaSet: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF stExternalParaSet <> NULL THEN
       value := stExternalParaSet^;
       // 또는 stExternalParaSet.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: stExternalParaSet');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(stExternalParaSet) THEN
       value := stExternalParaSet.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   stExternalParaSet := ADR(targetVariable);
   IF stExternalParaSet = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF stExternalParaSet = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := stExternalParaSet^; // NULL 체크 없음!
value := stExternalParaSet.member; // NULL 체크 없음!

✅ 안전: IF stExternalParaSet <> NULL THEN
value := stExternalParaSet^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(stExternalParaSet) THEN
value := stExternalParaSet.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:1

설명: stExternalParaSet: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF stExternalParaSet <> NULL THEN
       value := stExternalParaSet^;
       // 또는 stExternalParaSet.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: stExternalParaSet');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(stExternalParaSet) THEN
       value := stExternalParaSet.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   stExternalParaSet := ADR(targetVariable);
   IF stExternalParaSet = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF stExternalParaSet = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := stExternalParaSet^; // NULL 체크 없음!
value := stExternalParaSet.member; // NULL 체크 없음!

✅ 안전: IF stExternalParaSet <> NULL THEN
value := stExternalParaSet^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(stExternalParaSet) THEN
value := stExternalParaSet.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:1

설명: stExternalParaSet: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF stExternalParaSet <> NULL THEN
       value := stExternalParaSet^;
       // 또는 stExternalParaSet.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: stExternalParaSet');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(stExternalParaSet) THEN
       value := stExternalParaSet.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   stExternalParaSet := ADR(targetVariable);
   IF stExternalParaSet = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF stExternalParaSet = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := stExternalParaSet^; // NULL 체크 없음!
value := stExternalParaSet.member; // NULL 체크 없음!

✅ 안전: IF stExternalParaSet <> NULL THEN
value := stExternalParaSet^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(stExternalParaSet) THEN
value := stExternalParaSet.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:1

설명: eInHeaterCtrlMode = eCTRL_MODE_ACTIVE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(eInHeaterCtrlMode - eCTRL_MODE_ACTIVE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF eInHeaterCtrlMode >= (eCTRL_MODE_ACTIVE - 1.0E-6) AND
      eInHeaterCtrlMode <= (eCTRL_MODE_ACTIVE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF eInHeaterCtrlMode >= eCTRL_MODE_ACTIVE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(eInHeaterCtrlMode * 10.0);
   intTarget := REAL_TO_DINT(eCTRL_MODE_ACTIVE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF eInHeaterCtrlMode = eCTRL_MODE_ACTIVE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(eInHeaterCtrlMode - eCTRL_MODE_ACTIVE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:1

설명: eInHeaterCtrlMode = eCTRL_MODE_PASSIVE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(eInHeaterCtrlMode - eCTRL_MODE_PASSIVE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF eInHeaterCtrlMode >= (eCTRL_MODE_PASSIVE - 1.0E-6) AND
      eInHeaterCtrlMode <= (eCTRL_MODE_PASSIVE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF eInHeaterCtrlMode >= eCTRL_MODE_PASSIVE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(eInHeaterCtrlMode * 10.0);
   intTarget := REAL_TO_DINT(eCTRL_MODE_PASSIVE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF eInHeaterCtrlMode = eCTRL_MODE_PASSIVE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(eInHeaterCtrlMode - eCTRL_MODE_PASSIVE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:1

설명: eInHeaterCtrlMode = eCTRL_MODE_MANUAL: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(eInHeaterCtrlMode - eCTRL_MODE_MANUAL) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF eInHeaterCtrlMode >= (eCTRL_MODE_MANUAL - 1.0E-6) AND
      eInHeaterCtrlMode <= (eCTRL_MODE_MANUAL + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF eInHeaterCtrlMode >= eCTRL_MODE_MANUAL THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(eInHeaterCtrlMode * 10.0);
   intTarget := REAL_TO_DINT(eCTRL_MODE_MANUAL * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF eInHeaterCtrlMode = eCTRL_MODE_MANUAL THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(eInHeaterCtrlMode - eCTRL_MODE_MANUAL) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:1

설명: stPTParams: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF stPTParams <> NULL THEN
       value := stPTParams^;
       // 또는 stPTParams.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: stPTParams');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(stPTParams) THEN
       value := stPTParams.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   stPTParams := ADR(targetVariable);
   IF stPTParams = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF stPTParams = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := stPTParams^; // NULL 체크 없음!
value := stPTParams.member; // NULL 체크 없음!

✅ 안전: IF stPTParams <> NULL THEN
value := stPTParams^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(stPTParams) THEN
value := stPTParams.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:1

설명: stPTParams: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF stPTParams <> NULL THEN
       value := stPTParams^;
       // 또는 stPTParams.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: stPTParams');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(stPTParams) THEN
       value := stPTParams.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   stPTParams := ADR(targetVariable);
   IF stPTParams = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF stPTParams = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := stPTParams^; // NULL 체크 없음!
value := stPTParams.member; // NULL 체크 없음!

✅ 안전: IF stPTParams <> NULL THEN
value := stPTParams^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(stPTParams) THEN
value := stPTParams.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:1

설명: stPTParams: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF stPTParams <> NULL THEN
       value := stPTParams^;
       // 또는 stPTParams.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: stPTParams');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(stPTParams) THEN
       value := stPTParams.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   stPTParams := ADR(targetVariable);
   IF stPTParams = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF stPTParams = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := stPTParams^; // NULL 체크 없음!
value := stPTParams.member; // NULL 체크 없음!

✅ 안전: IF stPTParams <> NULL THEN
value := stPTParams^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(stPTParams) THEN
value := stPTParams.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:1

설명: stPTParams: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF stPTParams <> NULL THEN
       value := stPTParams^;
       // 또는 stPTParams.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: stPTParams');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(stPTParams) THEN
       value := stPTParams.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   stPTParams := ADR(targetVariable);
   IF stPTParams = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF stPTParams = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := stPTParams^; // NULL 체크 없음!
value := stPTParams.member; // NULL 체크 없음!

✅ 안전: IF stPTParams <> NULL THEN
value := stPTParams^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(stPTParams) THEN
value := stPTParams.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:1

설명: stPTParams: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF stPTParams <> NULL THEN
       value := stPTParams^;
       // 또는 stPTParams.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: stPTParams');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(stPTParams) THEN
       value := stPTParams.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   stPTParams := ADR(targetVariable);
   IF stPTParams = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF stPTParams = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := stPTParams^; // NULL 체크 없음!
value := stPTParams.member; // NULL 체크 없음!

✅ 안전: IF stPTParams <> NULL THEN
value := stPTParams^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(stPTParams) THEN
value := stPTParams.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: tTimeOut: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF tTimeOut <> NULL THEN
       value := tTimeOut^;
       // 또는 tTimeOut.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: tTimeOut');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(tTimeOut) THEN
       value := tTimeOut.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   tTimeOut := ADR(targetVariable);
   IF tTimeOut = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF tTimeOut = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := tTimeOut^; // NULL 체크 없음!
value := tTimeOut.member; // NULL 체크 없음!

✅ 안전: IF tTimeOut <> NULL THEN
value := tTimeOut^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(tTimeOut) THEN
value := tTimeOut.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: tConnect: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF tConnect <> NULL THEN
       value := tConnect^;
       // 또는 tConnect.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: tConnect');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(tConnect) THEN
       value := tConnect.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   tConnect := ADR(targetVariable);
   IF tConnect = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF tConnect = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := tConnect^; // NULL 체크 없음!
value := tConnect.member; // NULL 체크 없음!

✅ 안전: IF tConnect <> NULL THEN
value := tConnect^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(tConnect) THEN
value := tConnect.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: tTimeOut: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF tTimeOut <> NULL THEN
       value := tTimeOut^;
       // 또는 tTimeOut.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: tTimeOut');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(tTimeOut) THEN
       value := tTimeOut.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   tTimeOut := ADR(targetVariable);
   IF tTimeOut = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF tTimeOut = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := tTimeOut^; // NULL 체크 없음!
value := tTimeOut.member; // NULL 체크 없음!

✅ 안전: IF tTimeOut <> NULL THEN
value := tTimeOut^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(tTimeOut) THEN
value := tTimeOut.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: tTimeDelay: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF tTimeDelay <> NULL THEN
       value := tTimeDelay^;
       // 또는 tTimeDelay.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: tTimeDelay');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(tTimeDelay) THEN
       value := tTimeDelay.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   tTimeDelay := ADR(targetVariable);
   IF tTimeDelay = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF tTimeDelay = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := tTimeDelay^; // NULL 체크 없음!
value := tTimeDelay.member; // NULL 체크 없음!

✅ 안전: IF tTimeDelay <> NULL THEN
value := tTimeDelay^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(tTimeDelay) THEN
value := tTimeDelay.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: ModBusTCP_Mini8_FB_Diagnose: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ModBusTCP_Mini8_FB_Diagnose <> NULL THEN
       value := ModBusTCP_Mini8_FB_Diagnose^;
       // 또는 ModBusTCP_Mini8_FB_Diagnose.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ModBusTCP_Mini8_FB_Diagnose');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ModBusTCP_Mini8_FB_Diagnose) THEN
       value := ModBusTCP_Mini8_FB_Diagnose.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ModBusTCP_Mini8_FB_Diagnose := ADR(targetVariable);
   IF ModBusTCP_Mini8_FB_Diagnose = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ModBusTCP_Mini8_FB_Diagnose = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ModBusTCP_Mini8_FB_Diagnose^; // NULL 체크 없음!
value := ModBusTCP_Mini8_FB_Diagnose.member; // NULL 체크 없음!

✅ 안전: IF ModBusTCP_Mini8_FB_Diagnose <> NULL THEN
value := ModBusTCP_Mini8_FB_Diagnose^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ModBusTCP_Mini8_FB_Diagnose) THEN
value := ModBusTCP_Mini8_FB_Diagnose.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: SEQ_Driver_Mini8_ModBusTCP: 333줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Driver_Mini8_ModBusTCP = 333줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: bParameterSet = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(bParameterSet - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF bParameterSet >= (FALSE - 1.0E-6) AND
      bParameterSet <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF bParameterSet >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(bParameterSet * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF bParameterSet = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(bParameterSet - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: bModBusError = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(bModBusError - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF bModBusError >= (FALSE - 1.0E-6) AND
      bModBusError <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF bModBusError >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(bModBusError * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF bModBusError = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(bModBusError - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: bSpike_TC_Sensor_Break = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(bSpike_TC_Sensor_Break - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF bSpike_TC_Sensor_Break >= (FALSE - 1.0E-6) AND
      bSpike_TC_Sensor_Break <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF bSpike_TC_Sensor_Break >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(bSpike_TC_Sensor_Break * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF bSpike_TC_Sensor_Break = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(bSpike_TC_Sensor_Break - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: bProfile_TC_Sensor_Break = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(bProfile_TC_Sensor_Break - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF bProfile_TC_Sensor_Break >= (FALSE - 1.0E-6) AND
      bProfile_TC_Sensor_Break <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF bProfile_TC_Sensor_Break >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(bProfile_TC_Sensor_Break * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF bProfile_TC_Sensor_Break = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(bProfile_TC_Sensor_Break - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: bOverTemp_TC_Sensor_Break = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(bOverTemp_TC_Sensor_Break - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF bOverTemp_TC_Sensor_Break >= (FALSE - 1.0E-6) AND
      bOverTemp_TC_Sensor_Break <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF bOverTemp_TC_Sensor_Break >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(bOverTemp_TC_Sensor_Break * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF bOverTemp_TC_Sensor_Break = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(bOverTemp_TC_Sensor_Break - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_Mini8_Input_Channel]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Mini8_Input_Channel >= 1 AND
      1..cMAX_Mini8_Input_Channel <= 10 THEN
       value := ARRAY[1..cMAX_Mini8_Input_Channel];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Mini8_Input_Channel, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Mini8_Input_Channel >= ARRAY_MIN AND 1..cMAX_Mini8_Input_Channel <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Mini8_Input_Channel];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Mini8_Input_Channel]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Mini8_Input_Channel >= 1 AND 1..cMAX_Mini8_Input_Channel <= 10 THEN
value := ARRAY[1..cMAX_Mini8_Input_Channel];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_Mini8_Input_Channel]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Mini8_Input_Channel >= 1 AND
      1..cMAX_Mini8_Input_Channel <= 10 THEN
       value := ARRAY[1..cMAX_Mini8_Input_Channel];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Mini8_Input_Channel, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Mini8_Input_Channel >= ARRAY_MIN AND 1..cMAX_Mini8_Input_Channel <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Mini8_Input_Channel];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Mini8_Input_Channel]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Mini8_Input_Channel >= 1 AND 1..cMAX_Mini8_Input_Channel <= 10 THEN
value := ARRAY[1..cMAX_Mini8_Input_Channel];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_Mini8_Input_Channel]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Mini8_Input_Channel >= 1 AND
      1..cMAX_Mini8_Input_Channel <= 10 THEN
       value := ARRAY[1..cMAX_Mini8_Input_Channel];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Mini8_Input_Channel, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Mini8_Input_Channel >= ARRAY_MIN AND 1..cMAX_Mini8_Input_Channel <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Mini8_Input_Channel];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Mini8_Input_Channel]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Mini8_Input_Channel >= 1 AND 1..cMAX_Mini8_Input_Channel <= 10 THEN
value := ARRAY[1..cMAX_Mini8_Input_Channel];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_Mini8_Input_Channel]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Mini8_Input_Channel >= 1 AND
      1..cMAX_Mini8_Input_Channel <= 10 THEN
       value := ARRAY[1..cMAX_Mini8_Input_Channel];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Mini8_Input_Channel, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Mini8_Input_Channel >= ARRAY_MIN AND 1..cMAX_Mini8_Input_Channel <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Mini8_Input_Channel];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Mini8_Input_Channel]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Mini8_Input_Channel >= 1 AND 1..cMAX_Mini8_Input_Channel <= 10 THEN
value := ARRAY[1..cMAX_Mini8_Input_Channel];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_Mini8_Input_Channel]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Mini8_Input_Channel >= 1 AND
      1..cMAX_Mini8_Input_Channel <= 10 THEN
       value := ARRAY[1..cMAX_Mini8_Input_Channel];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Mini8_Input_Channel, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Mini8_Input_Channel >= ARRAY_MIN AND 1..cMAX_Mini8_Input_Channel <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Mini8_Input_Channel];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Mini8_Input_Channel]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Mini8_Input_Channel >= 1 AND 1..cMAX_Mini8_Input_Channel <= 10 THEN
value := ARRAY[1..cMAX_Mini8_Input_Channel];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_Mini8_Input_Channel]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Mini8_Input_Channel >= 1 AND
      1..cMAX_Mini8_Input_Channel <= 10 THEN
       value := ARRAY[1..cMAX_Mini8_Input_Channel];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Mini8_Input_Channel, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Mini8_Input_Channel >= ARRAY_MIN AND 1..cMAX_Mini8_Input_Channel <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Mini8_Input_Channel];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Mini8_Input_Channel]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Mini8_Input_Channel >= 1 AND 1..cMAX_Mini8_Input_Channel <= 10 THEN
value := ARRAY[1..cMAX_Mini8_Input_Channel];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_Mini8_Input_Channel]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Mini8_Input_Channel >= 1 AND
      1..cMAX_Mini8_Input_Channel <= 10 THEN
       value := ARRAY[1..cMAX_Mini8_Input_Channel];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Mini8_Input_Channel, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Mini8_Input_Channel >= ARRAY_MIN AND 1..cMAX_Mini8_Input_Channel <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Mini8_Input_Channel];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Mini8_Input_Channel]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Mini8_Input_Channel >= 1 AND 1..cMAX_Mini8_Input_Channel <= 10 THEN
value := ARRAY[1..cMAX_Mini8_Input_Channel];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_Mini8_Input_Channel]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Mini8_Input_Channel >= 1 AND
      1..cMAX_Mini8_Input_Channel <= 10 THEN
       value := ARRAY[1..cMAX_Mini8_Input_Channel];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Mini8_Input_Channel, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Mini8_Input_Channel >= ARRAY_MIN AND 1..cMAX_Mini8_Input_Channel <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Mini8_Input_Channel];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Mini8_Input_Channel]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Mini8_Input_Channel >= 1 AND 1..cMAX_Mini8_Input_Channel <= 10 THEN
value := ARRAY[1..cMAX_Mini8_Input_Channel];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: fPV_TC_Sensor_Array[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := fPV_TC_Sensor_Array[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := fPV_TC_Sensor_Array[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := fPV_TC_Sensor_Array[i];
   END_IF

예시:

❌ 위험: value := fPV_TC_Sensor_Array[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := fPV_TC_Sensor_Array[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: ioTC_Power_Module_OK: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF ioTC_Power_Module_OK <> NULL THEN
       value := ioTC_Power_Module_OK^;
       // 또는 ioTC_Power_Module_OK.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: ioTC_Power_Module_OK');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(ioTC_Power_Module_OK) THEN
       value := ioTC_Power_Module_OK.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   ioTC_Power_Module_OK := ADR(targetVariable);
   IF ioTC_Power_Module_OK = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF ioTC_Power_Module_OK = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := ioTC_Power_Module_OK^; // NULL 체크 없음!
value := ioTC_Power_Module_OK.member; // NULL 체크 없음!

✅ 안전: IF ioTC_Power_Module_OK <> NULL THEN
value := ioTC_Power_Module_OK^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(ioTC_Power_Module_OK) THEN
value := ioTC_Power_Module_OK.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: bParameterSet = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(bParameterSet - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF bParameterSet >= (FALSE - 1.0E-6) AND
      bParameterSet <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF bParameterSet >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(bParameterSet * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF bParameterSet = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(bParameterSet - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: AI_Spike_Temp[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := AI_Spike_Temp[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := AI_Spike_Temp[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := AI_Spike_Temp[i];
   END_IF

예시:

❌ 위험: value := AI_Spike_Temp[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := AI_Spike_Temp[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: ioTC_Spike_Temp[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioTC_Spike_Temp[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioTC_Spike_Temp[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioTC_Spike_Temp[i];
   END_IF

예시:

❌ 위험: value := ioTC_Spike_Temp[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioTC_Spike_Temp[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: AI_Over_Temp[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := AI_Over_Temp[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := AI_Over_Temp[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := AI_Over_Temp[i];
   END_IF

예시:

❌ 위험: value := AI_Over_Temp[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := AI_Over_Temp[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: ioTC_Over_Temp[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioTC_Over_Temp[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioTC_Over_Temp[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioTC_Over_Temp[i];
   END_IF

예시:

❌ 위험: value := ioTC_Over_Temp[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioTC_Over_Temp[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: AI_Profile_Temp[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := AI_Profile_Temp[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := AI_Profile_Temp[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := AI_Profile_Temp[i];
   END_IF

예시:

❌ 위험: value := AI_Profile_Temp[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := AI_Profile_Temp[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: AI_Spike_Temp[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := AI_Spike_Temp[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := AI_Spike_Temp[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := AI_Spike_Temp[i];
   END_IF

예시:

❌ 위험: value := AI_Spike_Temp[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := AI_Spike_Temp[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: AI_Profile_Temp[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := AI_Profile_Temp[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := AI_Profile_Temp[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := AI_Profile_Temp[i];
   END_IF

예시:

❌ 위험: value := AI_Profile_Temp[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := AI_Profile_Temp[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: ioTC_Profile_Temp[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioTC_Profile_Temp[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioTC_Profile_Temp[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioTC_Profile_Temp[i];
   END_IF

예시:

❌ 위험: value := ioTC_Profile_Temp[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioTC_Profile_Temp[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: DI_Profile_Sensor_Break[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DI_Profile_Sensor_Break[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DI_Profile_Sensor_Break[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DI_Profile_Sensor_Break[i];
   END_IF

예시:

❌ 위험: value := DI_Profile_Sensor_Break[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DI_Profile_Sensor_Break[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: DI_Profile_Sensor_Break[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DI_Profile_Sensor_Break[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DI_Profile_Sensor_Break[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DI_Profile_Sensor_Break[i];
   END_IF

예시:

❌ 위험: value := DI_Profile_Sensor_Break[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DI_Profile_Sensor_Break[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: ioTC_Profile_Module_Status[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioTC_Profile_Module_Status[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioTC_Profile_Module_Status[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioTC_Profile_Module_Status[i];
   END_IF

예시:

❌ 위험: value := ioTC_Profile_Module_Status[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioTC_Profile_Module_Status[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: DI_Spike_Sensor_Break[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DI_Spike_Sensor_Break[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DI_Spike_Sensor_Break[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DI_Spike_Sensor_Break[i];
   END_IF

예시:

❌ 위험: value := DI_Spike_Sensor_Break[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DI_Spike_Sensor_Break[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: ioTC_Spike_Module_Status[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioTC_Spike_Module_Status[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioTC_Spike_Module_Status[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioTC_Spike_Module_Status[i];
   END_IF

예시:

❌ 위험: value := ioTC_Spike_Module_Status[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioTC_Spike_Module_Status[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: DI_OverTemp_Sensor_Break[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := DI_OverTemp_Sensor_Break[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := DI_OverTemp_Sensor_Break[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := DI_OverTemp_Sensor_Break[i];
   END_IF

예시:

❌ 위험: value := DI_OverTemp_Sensor_Break[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := DI_OverTemp_Sensor_Break[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: ioTC_Over_Module_Status[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := ioTC_Over_Module_Status[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := ioTC_Over_Module_Status[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := ioTC_Over_Module_Status[i];
   END_IF

예시:

❌ 위험: value := ioTC_Over_Module_Status[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := ioTC_Over_Module_Status[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: tConnect: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF tConnect <> NULL THEN
       value := tConnect^;
       // 또는 tConnect.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: tConnect');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(tConnect) THEN
       value := tConnect.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   tConnect := ADR(targetVariable);
   IF tConnect = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF tConnect = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := tConnect^; // NULL 체크 없음!
value := tConnect.member; // NULL 체크 없음!

✅ 안전: IF tConnect <> NULL THEN
value := tConnect^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(tConnect) THEN
value := tConnect.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: tTimeOut: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF tTimeOut <> NULL THEN
       value := tTimeOut^;
       // 또는 tTimeOut.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: tTimeOut');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(tTimeOut) THEN
       value := tTimeOut.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   tTimeOut := ADR(targetVariable);
   IF tTimeOut = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF tTimeOut = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := tTimeOut^; // NULL 체크 없음!
value := tTimeOut.member; // NULL 체크 없음!

✅ 안전: IF tTimeOut <> NULL THEN
value := tTimeOut^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(tTimeOut) THEN
value := tTimeOut.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: SEQ_Driver_X20_ModBusTCP: 830줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Driver_X20_ModBusTCP = 830줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: bParameterSet = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(bParameterSet - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF bParameterSet >= (FALSE - 1.0E-6) AND
      bParameterSet <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF bParameterSet >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(bParameterSet * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF bParameterSet = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(bParameterSet - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: ARRAY[1..72]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..72 >= 1 AND
      1..72 <= 10 THEN
       value := ARRAY[1..72];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..72, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..72 >= ARRAY_MIN AND 1..72 <= ARRAY_MAX THEN
       value := ARRAY[1..72];
   END_IF

예시:

❌ 위험: value := ARRAY[1..72]; // 범위 검사 없음!

✅ 안전: IF 1..72 >= 1 AND 1..72 <= 10 THEN
value := ARRAY[1..72];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: ARRAY[1..72]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..72 >= 1 AND
      1..72 <= 10 THEN
       value := ARRAY[1..72];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..72, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..72 >= ARRAY_MIN AND 1..72 <= ARRAY_MAX THEN
       value := ARRAY[1..72];
   END_IF

예시:

❌ 위험: value := ARRAY[1..72]; // 범위 검사 없음!

✅ 안전: IF 1..72 >= 1 AND 1..72 <= 10 THEN
value := ARRAY[1..72];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_TC_Channel]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_TC_Channel >= 1 AND
      1..cMAX_TC_Channel <= 10 THEN
       value := ARRAY[1..cMAX_TC_Channel];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_TC_Channel, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_TC_Channel >= ARRAY_MIN AND 1..cMAX_TC_Channel <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_TC_Channel];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_TC_Channel]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_TC_Channel >= 1 AND 1..cMAX_TC_Channel <= 10 THEN
value := ARRAY[1..cMAX_TC_Channel];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_CJC_Channel]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_CJC_Channel >= 1 AND
      1..cMAX_CJC_Channel <= 10 THEN
       value := ARRAY[1..cMAX_CJC_Channel];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_CJC_Channel, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_CJC_Channel >= ARRAY_MIN AND 1..cMAX_CJC_Channel <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_CJC_Channel];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_CJC_Channel]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_CJC_Channel >= 1 AND 1..cMAX_CJC_Channel <= 10 THEN
value := ARRAY[1..cMAX_CJC_Channel];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_CJC_Channel]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_CJC_Channel >= 1 AND
      1..cMAX_CJC_Channel <= 10 THEN
       value := ARRAY[1..cMAX_CJC_Channel];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_CJC_Channel, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_CJC_Channel >= ARRAY_MIN AND 1..cMAX_CJC_Channel <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_CJC_Channel];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_CJC_Channel]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_CJC_Channel >= 1 AND 1..cMAX_CJC_Channel <= 10 THEN
value := ARRAY[1..cMAX_CJC_Channel];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_Version_Channel]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Version_Channel >= 1 AND
      1..cMAX_Version_Channel <= 10 THEN
       value := ARRAY[1..cMAX_Version_Channel];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Version_Channel, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Version_Channel >= ARRAY_MIN AND 1..cMAX_Version_Channel <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Version_Channel];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Version_Channel]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Version_Channel >= 1 AND 1..cMAX_Version_Channel <= 10 THEN
value := ARRAY[1..cMAX_Version_Channel];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_IO_Module]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_IO_Module >= 1 AND
      1..cMAX_IO_Module <= 10 THEN
       value := ARRAY[1..cMAX_IO_Module];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_IO_Module, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_IO_Module >= ARRAY_MIN AND 1..cMAX_IO_Module <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_IO_Module];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_IO_Module]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_IO_Module >= 1 AND 1..cMAX_IO_Module <= 10 THEN
value := ARRAY[1..cMAX_IO_Module];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: ARRAY[1..3]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..3 >= 1 AND
      1..3 <= 10 THEN
       value := ARRAY[1..3];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..3, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..3 >= ARRAY_MIN AND 1..3 <= ARRAY_MAX THEN
       value := ARRAY[1..3];
   END_IF

예시:

❌ 위험: value := ARRAY[1..3]; // 범위 검사 없음!

✅ 안전: IF 1..3 >= 1 AND 1..3 <= 10 THEN
value := ARRAY[1..3];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_TC_Channel]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_TC_Channel >= 1 AND
      1..cMAX_TC_Channel <= 10 THEN
       value := ARRAY[1..cMAX_TC_Channel];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_TC_Channel, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_TC_Channel >= ARRAY_MIN AND 1..cMAX_TC_Channel <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_TC_Channel];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_TC_Channel]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_TC_Channel >= 1 AND 1..cMAX_TC_Channel <= 10 THEN
value := ARRAY[1..cMAX_TC_Channel];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: ARRAY[1..3]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..3 >= 1 AND
      1..3 <= 10 THEN
       value := ARRAY[1..3];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..3, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..3 >= ARRAY_MIN AND 1..3 <= ARRAY_MAX THEN
       value := ARRAY[1..3];
   END_IF

예시:

❌ 위험: value := ARRAY[1..3]; // 범위 검사 없음!

✅ 안전: IF 1..3 >= 1 AND 1..3 <= 10 THEN
value := ARRAY[1..3];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_TC_Channel]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_TC_Channel >= 1 AND
      1..cMAX_TC_Channel <= 10 THEN
       value := ARRAY[1..cMAX_TC_Channel];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_TC_Channel, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_TC_Channel >= ARRAY_MIN AND 1..cMAX_TC_Channel <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_TC_Channel];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_TC_Channel]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_TC_Channel >= 1 AND 1..cMAX_TC_Channel <= 10 THEN
value := ARRAY[1..cMAX_TC_Channel];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: ARRAY[1..3]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..3 >= 1 AND
      1..3 <= 10 THEN
       value := ARRAY[1..3];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..3, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..3 >= ARRAY_MIN AND 1..3 <= ARRAY_MAX THEN
       value := ARRAY[1..3];
   END_IF

예시:

❌ 위험: value := ARRAY[1..3]; // 범위 검사 없음!

✅ 안전: IF 1..3 >= 1 AND 1..3 <= 10 THEN
value := ARRAY[1..3];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_TC_Channel]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_TC_Channel >= 1 AND
      1..cMAX_TC_Channel <= 10 THEN
       value := ARRAY[1..cMAX_TC_Channel];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_TC_Channel, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_TC_Channel >= ARRAY_MIN AND 1..cMAX_TC_Channel <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_TC_Channel];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_TC_Channel]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_TC_Channel >= 1 AND 1..cMAX_TC_Channel <= 10 THEN
value := ARRAY[1..cMAX_TC_Channel];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_Heater_SCR]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_SCR >= 1 AND
      1..cMAX_Heater_SCR <= 10 THEN
       value := ARRAY[1..cMAX_Heater_SCR];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_SCR, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_SCR >= ARRAY_MIN AND 1..cMAX_Heater_SCR <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_SCR];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_SCR]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_SCR >= 1 AND 1..cMAX_Heater_SCR <= 10 THEN
value := ARRAY[1..cMAX_Heater_SCR];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: SEQ_Temp_Control: 1613줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Temp_Control = 1613줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Zone >= 1 AND
      1..cMAX_Heater_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Zone >= 1 AND 1..cMAX_Heater_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Function\F_TrendData_RealToString.TcPOU:1

설명: Loop = cFRP_oMode_LogNum: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Loop - cFRP_oMode_LogNum) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Loop >= (cFRP_oMode_LogNum - 1.0E-6) AND
      Loop <= (cFRP_oMode_LogNum + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Loop >= cFRP_oMode_LogNum THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Loop * 10.0);
   intTarget := REAL_TO_DINT(cFRP_oMode_LogNum * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Loop = cFRP_oMode_LogNum THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Loop - cFRP_oMode_LogNum) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Function\F_TrendData_RealToString.TcPOU:1

설명: realData = 1: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(realData - 1) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF realData >= (1 - 1.0E-6) AND
      realData <= (1 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF realData >= 1 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(realData * 10.0);
   intTarget := REAL_TO_DINT(1 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF realData = 1 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(realData - 1) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Function\F_TrendData_RealToString.TcPOU:1

설명: realData = 2: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(realData - 2) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF realData >= (2 - 1.0E-6) AND
      realData <= (2 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF realData >= 2 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(realData * 10.0);
   intTarget := REAL_TO_DINT(2 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF realData = 2 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(realData - 2) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Function\F_TrendData_RealToString.TcPOU:1

설명: realData = 3: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(realData - 3) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF realData >= (3 - 1.0E-6) AND
      realData <= (3 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF realData >= 3 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(realData * 10.0);
   intTarget := REAL_TO_DINT(3 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF realData = 3 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(realData - 3) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Function\F_TrendData_RealToString.TcPOU:1

설명: realData = 4: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(realData - 4) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF realData >= (4 - 1.0E-6) AND
      realData <= (4 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF realData >= 4 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(realData * 10.0);
   intTarget := REAL_TO_DINT(4 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF realData = 4 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(realData - 4) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Function\F_TrendData_RealToString.TcPOU:1

설명: realData = 5: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(realData - 5) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF realData >= (5 - 1.0E-6) AND
      realData <= (5 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF realData >= 5 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(realData * 10.0);
   intTarget := REAL_TO_DINT(5 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF realData = 5 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(realData - 5) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Function\F_TrendData_RealToString.TcPOU:1

설명: Log_Title[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := Log_Title[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := Log_Title[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := Log_Title[Loop];
   END_IF

예시:

❌ 위험: value := Log_Title[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := Log_Title[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Function\F_TrendData_RealToString.TcPOU:1

설명: Log_Title[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := Log_Title[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := Log_Title[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := Log_Title[Loop];
   END_IF

예시:

❌ 위험: value := Log_Title[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := Log_Title[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Function\F_TrendData_RealToString.TcPOU:1

설명: Log_Title[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := Log_Title[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := Log_Title[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := Log_Title[Loop];
   END_IF

예시:

❌ 위험: value := Log_Title[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := Log_Title[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: Read_Trig: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Read_Trig <> NULL THEN
       value := Read_Trig^;
       // 또는 Read_Trig.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Read_Trig');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Read_Trig) THEN
       value := Read_Trig.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Read_Trig := ADR(targetVariable);
   IF Read_Trig = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Read_Trig = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Read_Trig^; // NULL 체크 없음!
value := Read_Trig.member; // NULL 체크 없음!

✅ 안전: IF Read_Trig <> NULL THEN
value := Read_Trig^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Read_Trig) THEN
value := Read_Trig.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: 5: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 5 <> NULL THEN
       value := 5^;
       // 또는 5.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 5');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(5) THEN
       value := 5.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   5 := ADR(targetVariable);
   IF 5 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 5 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 5^; // NULL 체크 없음!
value := 5.member; // NULL 체크 없음!

✅ 안전: IF 5 <> NULL THEN
value := 5^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(5) THEN
value := 5.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: 0: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 0 <> NULL THEN
       value := 0^;
       // 또는 0.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 0');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(0) THEN
       value := 0.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   0 := ADR(targetVariable);
   IF 0 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 0 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 0^; // NULL 체크 없음!
value := 0.member; // NULL 체크 없음!

✅ 안전: IF 0 <> NULL THEN
value := 0^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(0) THEN
value := 0.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: 4: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF 4 <> NULL THEN
       value := 4^;
       // 또는 4.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: 4');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(4) THEN
       value := 4.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   4 := ADR(targetVariable);
   IF 4 = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF 4 = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := 4^; // NULL 체크 없음!
value := 4.member; // NULL 체크 없음!

✅ 안전: IF 4 <> NULL THEN
value := 4^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(4) THEN
value := 4.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: Read_Trig: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Read_Trig <> NULL THEN
       value := Read_Trig^;
       // 또는 Read_Trig.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Read_Trig');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Read_Trig) THEN
       value := Read_Trig.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Read_Trig := ADR(targetVariable);
   IF Read_Trig = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Read_Trig = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Read_Trig^; // NULL 체크 없음!
value := Read_Trig.member; // NULL 체크 없음!

✅ 안전: IF Read_Trig <> NULL THEN
value := Read_Trig^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Read_Trig) THEN
value := Read_Trig.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: Read_Write_Timer: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Read_Write_Timer <> NULL THEN
       value := Read_Write_Timer^;
       // 또는 Read_Write_Timer.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Read_Write_Timer');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Read_Write_Timer) THEN
       value := Read_Write_Timer.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Read_Write_Timer := ADR(targetVariable);
   IF Read_Write_Timer = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Read_Write_Timer = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Read_Write_Timer^; // NULL 체크 없음!
value := Read_Write_Timer.member; // NULL 체크 없음!

✅ 안전: IF Read_Write_Timer <> NULL THEN
value := Read_Write_Timer^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Read_Write_Timer) THEN
value := Read_Write_Timer.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: Read_Write_Timer: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Read_Write_Timer <> NULL THEN
       value := Read_Write_Timer^;
       // 또는 Read_Write_Timer.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Read_Write_Timer');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Read_Write_Timer) THEN
       value := Read_Write_Timer.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Read_Write_Timer := ADR(targetVariable);
   IF Read_Write_Timer = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Read_Write_Timer = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Read_Write_Timer^; // NULL 체크 없음!
value := Read_Write_Timer.member; // NULL 체크 없음!

✅ 안전: IF Read_Write_Timer <> NULL THEN
value := Read_Write_Timer^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Read_Write_Timer) THEN
value := Read_Write_Timer.member;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: ARRAY[0..cMAX_HW_ALARM_SIZE]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 0..cMAX_HW_ALARM_SIZE >= 1 AND
      0..cMAX_HW_ALARM_SIZE <= 10 THEN
       value := ARRAY[0..cMAX_HW_ALARM_SIZE];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 0..cMAX_HW_ALARM_SIZE, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 0..cMAX_HW_ALARM_SIZE >= ARRAY_MIN AND 0..cMAX_HW_ALARM_SIZE <= ARRAY_MAX THEN
       value := ARRAY[0..cMAX_HW_ALARM_SIZE];
   END_IF

예시:

❌ 위험: value := ARRAY[0..cMAX_HW_ALARM_SIZE]; // 범위 검사 없음!

✅ 안전: IF 0..cMAX_HW_ALARM_SIZE >= 1 AND 0..cMAX_HW_ALARM_SIZE <= 10 THEN
value := ARRAY[0..cMAX_HW_ALARM_SIZE];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: ARRAY[0..2]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 0..2 >= 1 AND
      0..2 <= 10 THEN
       value := ARRAY[0..2];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 0..2, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 0..2 >= ARRAY_MIN AND 0..2 <= ARRAY_MAX THEN
       value := ARRAY[0..2];
   END_IF

예시:

❌ 위험: value := ARRAY[0..2]; // 범위 검사 없음!

✅ 안전: IF 0..2 >= 1 AND 0..2 <= 10 THEN
value := ARRAY[0..2];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: ARRAY[1..32]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..32 >= 1 AND
      1..32 <= 10 THEN
       value := ARRAY[1..32];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..32, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..32 >= ARRAY_MIN AND 1..32 <= ARRAY_MAX THEN
       value := ARRAY[1..32];
   END_IF

예시:

❌ 위험: value := ARRAY[1..32]; // 범위 검사 없음!

✅ 안전: IF 1..32 >= 1 AND 1..32 <= 10 THEN
value := ARRAY[1..32];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: ARRAY[1..32]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..32 >= 1 AND
      1..32 <= 10 THEN
       value := ARRAY[1..32];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..32, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..32 >= ARRAY_MIN AND 1..32 <= ARRAY_MAX THEN
       value := ARRAY[1..32];
   END_IF

예시:

❌ 위험: value := ARRAY[1..32]; // 범위 검사 없음!

✅ 안전: IF 1..32 >= 1 AND 1..32 <= 10 THEN
value := ARRAY[1..32];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: fbAlarm[23001 + i * 8 + 0]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 23001 + i * 8 + 0 >= 1 AND
      23001 + i * 8 + 0 <= 10 THEN
       value := fbAlarm[23001 + i * 8 + 0];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 23001 + i * 8 + 0, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 23001 + i * 8 + 0 >= ARRAY_MIN AND 23001 + i * 8 + 0 <= ARRAY_MAX THEN
       value := fbAlarm[23001 + i * 8 + 0];
   END_IF

예시:

❌ 위험: value := fbAlarm[23001 + i * 8 + 0]; // 범위 검사 없음!

✅ 안전: IF 23001 + i * 8 + 0 >= 1 AND 23001 + i * 8 + 0 <= 10 THEN
value := fbAlarm[23001 + i * 8 + 0];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_ALARM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := HW_ALARM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := HW_ALARM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := HW_ALARM[i];
   END_IF

예시:

❌ 위험: value := HW_ALARM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := HW_ALARM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: fbAlarm[23001 + i * 8 + 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 23001 + i * 8 + 1 >= 1 AND
      23001 + i * 8 + 1 <= 10 THEN
       value := fbAlarm[23001 + i * 8 + 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 23001 + i * 8 + 1, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 23001 + i * 8 + 1 >= ARRAY_MIN AND 23001 + i * 8 + 1 <= ARRAY_MAX THEN
       value := fbAlarm[23001 + i * 8 + 1];
   END_IF

예시:

❌ 위험: value := fbAlarm[23001 + i * 8 + 1]; // 범위 검사 없음!

✅ 안전: IF 23001 + i * 8 + 1 >= 1 AND 23001 + i * 8 + 1 <= 10 THEN
value := fbAlarm[23001 + i * 8 + 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_ALARM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := HW_ALARM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := HW_ALARM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := HW_ALARM[i];
   END_IF

예시:

❌ 위험: value := HW_ALARM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := HW_ALARM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: fbAlarm[23001 + i * 8 + 2]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 23001 + i * 8 + 2 >= 1 AND
      23001 + i * 8 + 2 <= 10 THEN
       value := fbAlarm[23001 + i * 8 + 2];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 23001 + i * 8 + 2, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 23001 + i * 8 + 2 >= ARRAY_MIN AND 23001 + i * 8 + 2 <= ARRAY_MAX THEN
       value := fbAlarm[23001 + i * 8 + 2];
   END_IF

예시:

❌ 위험: value := fbAlarm[23001 + i * 8 + 2]; // 범위 검사 없음!

✅ 안전: IF 23001 + i * 8 + 2 >= 1 AND 23001 + i * 8 + 2 <= 10 THEN
value := fbAlarm[23001 + i * 8 + 2];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_ALARM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := HW_ALARM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := HW_ALARM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := HW_ALARM[i];
   END_IF

예시:

❌ 위험: value := HW_ALARM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := HW_ALARM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: fbAlarm[23001 + i * 8 + 3]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 23001 + i * 8 + 3 >= 1 AND
      23001 + i * 8 + 3 <= 10 THEN
       value := fbAlarm[23001 + i * 8 + 3];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 23001 + i * 8 + 3, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 23001 + i * 8 + 3 >= ARRAY_MIN AND 23001 + i * 8 + 3 <= ARRAY_MAX THEN
       value := fbAlarm[23001 + i * 8 + 3];
   END_IF

예시:

❌ 위험: value := fbAlarm[23001 + i * 8 + 3]; // 범위 검사 없음!

✅ 안전: IF 23001 + i * 8 + 3 >= 1 AND 23001 + i * 8 + 3 <= 10 THEN
value := fbAlarm[23001 + i * 8 + 3];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_ALARM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := HW_ALARM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := HW_ALARM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := HW_ALARM[i];
   END_IF

예시:

❌ 위험: value := HW_ALARM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := HW_ALARM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: fbAlarm[23001 + i * 8 + 4]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 23001 + i * 8 + 4 >= 1 AND
      23001 + i * 8 + 4 <= 10 THEN
       value := fbAlarm[23001 + i * 8 + 4];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 23001 + i * 8 + 4, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 23001 + i * 8 + 4 >= ARRAY_MIN AND 23001 + i * 8 + 4 <= ARRAY_MAX THEN
       value := fbAlarm[23001 + i * 8 + 4];
   END_IF

예시:

❌ 위험: value := fbAlarm[23001 + i * 8 + 4]; // 범위 검사 없음!

✅ 안전: IF 23001 + i * 8 + 4 >= 1 AND 23001 + i * 8 + 4 <= 10 THEN
value := fbAlarm[23001 + i * 8 + 4];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_ALARM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := HW_ALARM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := HW_ALARM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := HW_ALARM[i];
   END_IF

예시:

❌ 위험: value := HW_ALARM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := HW_ALARM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: fbAlarm[23001 + i * 8 + 5]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 23001 + i * 8 + 5 >= 1 AND
      23001 + i * 8 + 5 <= 10 THEN
       value := fbAlarm[23001 + i * 8 + 5];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 23001 + i * 8 + 5, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 23001 + i * 8 + 5 >= ARRAY_MIN AND 23001 + i * 8 + 5 <= ARRAY_MAX THEN
       value := fbAlarm[23001 + i * 8 + 5];
   END_IF

예시:

❌ 위험: value := fbAlarm[23001 + i * 8 + 5]; // 범위 검사 없음!

✅ 안전: IF 23001 + i * 8 + 5 >= 1 AND 23001 + i * 8 + 5 <= 10 THEN
value := fbAlarm[23001 + i * 8 + 5];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_ALARM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := HW_ALARM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := HW_ALARM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := HW_ALARM[i];
   END_IF

예시:

❌ 위험: value := HW_ALARM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := HW_ALARM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: fbAlarm[23001 + i * 8 + 6]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 23001 + i * 8 + 6 >= 1 AND
      23001 + i * 8 + 6 <= 10 THEN
       value := fbAlarm[23001 + i * 8 + 6];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 23001 + i * 8 + 6, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 23001 + i * 8 + 6 >= ARRAY_MIN AND 23001 + i * 8 + 6 <= ARRAY_MAX THEN
       value := fbAlarm[23001 + i * 8 + 6];
   END_IF

예시:

❌ 위험: value := fbAlarm[23001 + i * 8 + 6]; // 범위 검사 없음!

✅ 안전: IF 23001 + i * 8 + 6 >= 1 AND 23001 + i * 8 + 6 <= 10 THEN
value := fbAlarm[23001 + i * 8 + 6];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_ALARM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := HW_ALARM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := HW_ALARM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := HW_ALARM[i];
   END_IF

예시:

❌ 위험: value := HW_ALARM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := HW_ALARM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: fbAlarm[23001 + i * 8 + 7]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 23001 + i * 8 + 7 >= 1 AND
      23001 + i * 8 + 7 <= 10 THEN
       value := fbAlarm[23001 + i * 8 + 7];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 23001 + i * 8 + 7, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 23001 + i * 8 + 7 >= ARRAY_MIN AND 23001 + i * 8 + 7 <= ARRAY_MAX THEN
       value := fbAlarm[23001 + i * 8 + 7];
   END_IF

예시:

❌ 위험: value := fbAlarm[23001 + i * 8 + 7]; // 범위 검사 없음!

✅ 안전: IF 23001 + i * 8 + 7 >= 1 AND 23001 + i * 8 + 7 <= 10 THEN
value := fbAlarm[23001 + i * 8 + 7];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_ALARM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := HW_ALARM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := HW_ALARM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := HW_ALARM[i];
   END_IF

예시:

❌ 위험: value := HW_ALARM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := HW_ALARM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: fbAlarm[Alarm_Num]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Alarm_Num >= 1 AND
      Alarm_Num <= 10 THEN
       value := fbAlarm[Alarm_Num];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Alarm_Num, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Alarm_Num >= ARRAY_MIN AND Alarm_Num <= ARRAY_MAX THEN
       value := fbAlarm[Alarm_Num];
   END_IF

예시:

❌ 위험: value := fbAlarm[Alarm_Num]; // 범위 검사 없음!

✅ 안전: IF Alarm_Num >= 1 AND Alarm_Num <= 10 THEN
value := fbAlarm[Alarm_Num];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_ALARM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := HW_ALARM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := HW_ALARM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := HW_ALARM[i];
   END_IF

예시:

❌ 위험: value := HW_ALARM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := HW_ALARM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: fbAlarm[Alarm_Num + 1]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Alarm_Num + 1 >= 1 AND
      Alarm_Num + 1 <= 10 THEN
       value := fbAlarm[Alarm_Num + 1];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Alarm_Num + 1, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Alarm_Num + 1 >= ARRAY_MIN AND Alarm_Num + 1 <= ARRAY_MAX THEN
       value := fbAlarm[Alarm_Num + 1];
   END_IF

예시:

❌ 위험: value := fbAlarm[Alarm_Num + 1]; // 범위 검사 없음!

✅ 안전: IF Alarm_Num + 1 >= 1 AND Alarm_Num + 1 <= 10 THEN
value := fbAlarm[Alarm_Num + 1];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_ALARM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := HW_ALARM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := HW_ALARM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := HW_ALARM[i];
   END_IF

예시:

❌ 위험: value := HW_ALARM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := HW_ALARM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: fbAlarm[Alarm_Num + 2]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Alarm_Num + 2 >= 1 AND
      Alarm_Num + 2 <= 10 THEN
       value := fbAlarm[Alarm_Num + 2];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Alarm_Num + 2, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Alarm_Num + 2 >= ARRAY_MIN AND Alarm_Num + 2 <= ARRAY_MAX THEN
       value := fbAlarm[Alarm_Num + 2];
   END_IF

예시:

❌ 위험: value := fbAlarm[Alarm_Num + 2]; // 범위 검사 없음!

✅ 안전: IF Alarm_Num + 2 >= 1 AND Alarm_Num + 2 <= 10 THEN
value := fbAlarm[Alarm_Num + 2];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_ALARM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := HW_ALARM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := HW_ALARM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := HW_ALARM[i];
   END_IF

예시:

❌ 위험: value := HW_ALARM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := HW_ALARM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: fbAlarm[Alarm_Num + 3]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Alarm_Num + 3 >= 1 AND
      Alarm_Num + 3 <= 10 THEN
       value := fbAlarm[Alarm_Num + 3];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Alarm_Num + 3, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Alarm_Num + 3 >= ARRAY_MIN AND Alarm_Num + 3 <= ARRAY_MAX THEN
       value := fbAlarm[Alarm_Num + 3];
   END_IF

예시:

❌ 위험: value := fbAlarm[Alarm_Num + 3]; // 범위 검사 없음!

✅ 안전: IF Alarm_Num + 3 >= 1 AND Alarm_Num + 3 <= 10 THEN
value := fbAlarm[Alarm_Num + 3];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_ALARM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := HW_ALARM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := HW_ALARM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := HW_ALARM[i];
   END_IF

예시:

❌ 위험: value := HW_ALARM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := HW_ALARM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: fbAlarm[Alarm_Num + 4]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Alarm_Num + 4 >= 1 AND
      Alarm_Num + 4 <= 10 THEN
       value := fbAlarm[Alarm_Num + 4];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Alarm_Num + 4, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Alarm_Num + 4 >= ARRAY_MIN AND Alarm_Num + 4 <= ARRAY_MAX THEN
       value := fbAlarm[Alarm_Num + 4];
   END_IF

예시:

❌ 위험: value := fbAlarm[Alarm_Num + 4]; // 범위 검사 없음!

✅ 안전: IF Alarm_Num + 4 >= 1 AND Alarm_Num + 4 <= 10 THEN
value := fbAlarm[Alarm_Num + 4];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_ALARM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := HW_ALARM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := HW_ALARM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := HW_ALARM[i];
   END_IF

예시:

❌ 위험: value := HW_ALARM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := HW_ALARM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: fbAlarm[Alarm_Num + 5]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Alarm_Num + 5 >= 1 AND
      Alarm_Num + 5 <= 10 THEN
       value := fbAlarm[Alarm_Num + 5];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Alarm_Num + 5, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Alarm_Num + 5 >= ARRAY_MIN AND Alarm_Num + 5 <= ARRAY_MAX THEN
       value := fbAlarm[Alarm_Num + 5];
   END_IF

예시:

❌ 위험: value := fbAlarm[Alarm_Num + 5]; // 범위 검사 없음!

✅ 안전: IF Alarm_Num + 5 >= 1 AND Alarm_Num + 5 <= 10 THEN
value := fbAlarm[Alarm_Num + 5];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_ALARM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := HW_ALARM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := HW_ALARM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := HW_ALARM[i];
   END_IF

예시:

❌ 위험: value := HW_ALARM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := HW_ALARM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: fbAlarm[Alarm_Num + 6]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Alarm_Num + 6 >= 1 AND
      Alarm_Num + 6 <= 10 THEN
       value := fbAlarm[Alarm_Num + 6];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Alarm_Num + 6, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Alarm_Num + 6 >= ARRAY_MIN AND Alarm_Num + 6 <= ARRAY_MAX THEN
       value := fbAlarm[Alarm_Num + 6];
   END_IF

예시:

❌ 위험: value := fbAlarm[Alarm_Num + 6]; // 범위 검사 없음!

✅ 안전: IF Alarm_Num + 6 >= 1 AND Alarm_Num + 6 <= 10 THEN
value := fbAlarm[Alarm_Num + 6];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_ALARM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := HW_ALARM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := HW_ALARM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := HW_ALARM[i];
   END_IF

예시:

❌ 위험: value := HW_ALARM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := HW_ALARM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: fbAlarm[Alarm_Num + 7]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Alarm_Num + 7 >= 1 AND
      Alarm_Num + 7 <= 10 THEN
       value := fbAlarm[Alarm_Num + 7];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Alarm_Num + 7, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Alarm_Num + 7 >= ARRAY_MIN AND Alarm_Num + 7 <= ARRAY_MAX THEN
       value := fbAlarm[Alarm_Num + 7];
   END_IF

예시:

❌ 위험: value := fbAlarm[Alarm_Num + 7]; // 범위 검사 없음!

✅ 안전: IF Alarm_Num + 7 >= 1 AND Alarm_Num + 7 <= 10 THEN
value := fbAlarm[Alarm_Num + 7];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_ALARM[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := HW_ALARM[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := HW_ALARM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := HW_ALARM[i];
   END_IF

예시:

❌ 위험: value := HW_ALARM[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := HW_ALARM[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: pCollection: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pCollection <> NULL THEN
       value := pCollection^;
       // 또는 pCollection.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pCollection');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pCollection) THEN
       value := pCollection.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pCollection := ADR(targetVariable);
   IF pCollection = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pCollection = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pCollection^; // NULL 체크 없음!
value := pCollection.member; // NULL 체크 없음!

✅ 안전: IF pCollection <> NULL THEN
value := pCollection^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pCollection) THEN
value := pCollection.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: pCollection: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pCollection <> NULL THEN
       value := pCollection^;
       // 또는 pCollection.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pCollection');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pCollection) THEN
       value := pCollection.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pCollection := ADR(targetVariable);
   IF pCollection = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pCollection = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pCollection^; // NULL 체크 없음!
value := pCollection.member; // NULL 체크 없음!

✅ 안전: IF pCollection <> NULL THEN
value := pCollection^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pCollection) THEN
value := pCollection.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: pCollection: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pCollection <> NULL THEN
       value := pCollection^;
       // 또는 pCollection.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pCollection');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pCollection) THEN
       value := pCollection.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pCollection := ADR(targetVariable);
   IF pCollection = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pCollection = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pCollection^; // NULL 체크 없음!
value := pCollection.member; // NULL 체크 없음!

✅ 안전: IF pCollection <> NULL THEN
value := pCollection^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pCollection) THEN
value := pCollection.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: pCollection: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pCollection <> NULL THEN
       value := pCollection^;
       // 또는 pCollection.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pCollection');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pCollection) THEN
       value := pCollection.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pCollection := ADR(targetVariable);
   IF pCollection = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pCollection = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pCollection^; // NULL 체크 없음!
value := pCollection.member; // NULL 체크 없음!

✅ 안전: IF pCollection <> NULL THEN
value := pCollection^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pCollection) THEN
value := pCollection.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: pCollection: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pCollection <> NULL THEN
       value := pCollection^;
       // 또는 pCollection.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pCollection');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pCollection) THEN
       value := pCollection.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pCollection := ADR(targetVariable);
   IF pCollection = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pCollection = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pCollection^; // NULL 체크 없음!
value := pCollection.member; // NULL 체크 없음!

✅ 안전: IF pCollection <> NULL THEN
value := pCollection^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pCollection) THEN
value := pCollection.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: pCollection: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pCollection <> NULL THEN
       value := pCollection^;
       // 또는 pCollection.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pCollection');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pCollection) THEN
       value := pCollection.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pCollection := ADR(targetVariable);
   IF pCollection = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pCollection = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pCollection^; // NULL 체크 없음!
value := pCollection.member; // NULL 체크 없음!

✅ 안전: IF pCollection <> NULL THEN
value := pCollection^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pCollection) THEN
value := pCollection.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: pCollection: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pCollection <> NULL THEN
       value := pCollection^;
       // 또는 pCollection.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pCollection');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pCollection) THEN
       value := pCollection.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pCollection := ADR(targetVariable);
   IF pCollection = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pCollection = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pCollection^; // NULL 체크 없음!
value := pCollection.member; // NULL 체크 없음!

✅ 안전: IF pCollection <> NULL THEN
value := pCollection^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pCollection) THEN
value := pCollection.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: pCollection: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pCollection <> NULL THEN
       value := pCollection^;
       // 또는 pCollection.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pCollection');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pCollection) THEN
       value := pCollection.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pCollection := ADR(targetVariable);
   IF pCollection = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pCollection = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pCollection^; // NULL 체크 없음!
value := pCollection.member; // NULL 체크 없음!

✅ 안전: IF pCollection <> NULL THEN
value := pCollection^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pCollection) THEN
value := pCollection.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: pCollection: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pCollection <> NULL THEN
       value := pCollection^;
       // 또는 pCollection.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pCollection');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pCollection) THEN
       value := pCollection.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pCollection := ADR(targetVariable);
   IF pCollection = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pCollection = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pCollection^; // NULL 체크 없음!
value := pCollection.member; // NULL 체크 없음!

✅ 안전: IF pCollection <> NULL THEN
value := pCollection^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pCollection) THEN
value := pCollection.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: pCollection: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pCollection <> NULL THEN
       value := pCollection^;
       // 또는 pCollection.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pCollection');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pCollection) THEN
       value := pCollection.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pCollection := ADR(targetVariable);
   IF pCollection = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pCollection = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pCollection^; // NULL 체크 없음!
value := pCollection.member; // NULL 체크 없음!

✅ 안전: IF pCollection <> NULL THEN
value := pCollection^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pCollection) THEN
value := pCollection.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: pCollection: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pCollection <> NULL THEN
       value := pCollection^;
       // 또는 pCollection.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pCollection');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pCollection) THEN
       value := pCollection.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pCollection := ADR(targetVariable);
   IF pCollection = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pCollection = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pCollection^; // NULL 체크 없음!
value := pCollection.member; // NULL 체크 없음!

✅ 안전: IF pCollection <> NULL THEN
value := pCollection^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pCollection) THEN
value := pCollection.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: pCollection: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pCollection <> NULL THEN
       value := pCollection^;
       // 또는 pCollection.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pCollection');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pCollection) THEN
       value := pCollection.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pCollection := ADR(targetVariable);
   IF pCollection = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pCollection = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pCollection^; // NULL 체크 없음!
value := pCollection.member; // NULL 체크 없음!

✅ 안전: IF pCollection <> NULL THEN
value := pCollection^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pCollection) THEN
value := pCollection.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: pCollection: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pCollection <> NULL THEN
       value := pCollection^;
       // 또는 pCollection.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pCollection');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pCollection) THEN
       value := pCollection.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pCollection := ADR(targetVariable);
   IF pCollection = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pCollection = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pCollection^; // NULL 체크 없음!
value := pCollection.member; // NULL 체크 없음!

✅ 안전: IF pCollection <> NULL THEN
value := pCollection^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pCollection) THEN
value := pCollection.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: LOG_Dcoll: 532줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: LOG_Dcoll = 532줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: Boot = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Boot - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Boot >= (FALSE - 1.0E-6) AND
      Boot <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Boot >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Boot * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Boot = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Boot - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: Boot = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Boot - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Boot >= (FALSE - 1.0E-6) AND
      Boot <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Boot >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Boot * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Boot = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Boot - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: ARRAY[1..cMAX_Log_Dcoll_Max_Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Log_Dcoll_Max_Item >= 1 AND
      1..cMAX_Log_Dcoll_Max_Item <= 10 THEN
       value := ARRAY[1..cMAX_Log_Dcoll_Max_Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Log_Dcoll_Max_Item, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Log_Dcoll_Max_Item >= ARRAY_MIN AND 1..cMAX_Log_Dcoll_Max_Item <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Log_Dcoll_Max_Item];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Log_Dcoll_Max_Item]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Log_Dcoll_Max_Item >= 1 AND 1..cMAX_Log_Dcoll_Max_Item <= 10 THEN
value := ARRAY[1..cMAX_Log_Dcoll_Max_Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: ARRAY[1..cMAX_Log_Dcoll_Msg_Sum]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Log_Dcoll_Msg_Sum >= 1 AND
      1..cMAX_Log_Dcoll_Msg_Sum <= 10 THEN
       value := ARRAY[1..cMAX_Log_Dcoll_Msg_Sum];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Log_Dcoll_Msg_Sum, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Log_Dcoll_Msg_Sum >= ARRAY_MIN AND 1..cMAX_Log_Dcoll_Msg_Sum <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Log_Dcoll_Msg_Sum];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Log_Dcoll_Msg_Sum]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Log_Dcoll_Msg_Sum >= 1 AND 1..cMAX_Log_Dcoll_Msg_Sum <= 10 THEN
value := ARRAY[1..cMAX_Log_Dcoll_Msg_Sum];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: ARRAY[1..cMAX_Heater_Use_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Heater_Use_Zone >= 1 AND
      1..cMAX_Heater_Use_Zone <= 10 THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Heater_Use_Zone, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Heater_Use_Zone >= ARRAY_MIN AND 1..cMAX_Heater_Use_Zone <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Heater_Use_Zone];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Heater_Use_Zone]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Heater_Use_Zone >= 1 AND 1..cMAX_Heater_Use_Zone <= 10 THEN
value := ARRAY[1..cMAX_Heater_Use_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: Name[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := Name[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := Name[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := Name[Loop];
   END_IF

예시:

❌ 위험: value := Name[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := Name[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: Dcoll_Buffer[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Dcoll_Buffer[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Dcoll_Buffer[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Dcoll_Buffer[i];
   END_IF

예시:

❌ 위험: value := Dcoll_Buffer[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Dcoll_Buffer[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: Name[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := Name[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := Name[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := Name[Loop];
   END_IF

예시:

❌ 위험: value := Name[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := Name[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: Data_Min[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := Data_Min[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := Data_Min[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := Data_Min[Loop];
   END_IF

예시:

❌ 위험: value := Data_Min[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := Data_Min[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: Data_Max[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := Data_Max[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := Data_Max[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := Data_Max[Loop];
   END_IF

예시:

❌ 위험: value := Data_Max[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := Data_Max[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: Data_Avg[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := Data_Avg[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := Data_Avg[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := Data_Avg[Loop];
   END_IF

예시:

❌ 위험: value := Data_Avg[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := Data_Avg[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: Dcoll_Buffer[i]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF i >= 1 AND
      i <= 10 THEN
       value := Dcoll_Buffer[i];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, i, 10);
   value := Dcoll_Buffer[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF i >= ARRAY_MIN AND i <= ARRAY_MAX THEN
       value := Dcoll_Buffer[i];
   END_IF

예시:

❌ 위험: value := Dcoll_Buffer[i]; // 범위 검사 없음!

✅ 안전: IF i >= 1 AND i <= 10 THEN
value := Dcoll_Buffer[i];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: SX_RecipeCount_Name[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := SX_RecipeCount_Name[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := SX_RecipeCount_Name[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := SX_RecipeCount_Name[Loop];
   END_IF

예시:

❌ 위험: value := SX_RecipeCount_Name[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := SX_RecipeCount_Name[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: SX_RecipeCount_Item[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := SX_RecipeCount_Item[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := SX_RecipeCount_Item[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := SX_RecipeCount_Item[Loop];
   END_IF

예시:

❌ 위험: value := SX_RecipeCount_Item[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := SX_RecipeCount_Item[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: SX_RecipeCount_Current_Value[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := SX_RecipeCount_Current_Value[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := SX_RecipeCount_Current_Value[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := SX_RecipeCount_Current_Value[Loop];
   END_IF

예시:

❌ 위험: value := SX_RecipeCount_Current_Value[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := SX_RecipeCount_Current_Value[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: Name[DColl_Loop_Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF DColl_Loop_Item >= 1 AND
      DColl_Loop_Item <= 10 THEN
       value := Name[DColl_Loop_Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, DColl_Loop_Item, 10);
   value := Name[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF DColl_Loop_Item >= ARRAY_MIN AND DColl_Loop_Item <= ARRAY_MAX THEN
       value := Name[DColl_Loop_Item];
   END_IF

예시:

❌ 위험: value := Name[DColl_Loop_Item]; // 범위 검사 없음!

✅ 안전: IF DColl_Loop_Item >= 1 AND DColl_Loop_Item <= 10 THEN
value := Name[DColl_Loop_Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: Name[DColl_Loop_Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF DColl_Loop_Item >= 1 AND
      DColl_Loop_Item <= 10 THEN
       value := Name[DColl_Loop_Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, DColl_Loop_Item, 10);
   value := Name[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF DColl_Loop_Item >= ARRAY_MIN AND DColl_Loop_Item <= ARRAY_MAX THEN
       value := Name[DColl_Loop_Item];
   END_IF

예시:

❌ 위험: value := Name[DColl_Loop_Item]; // 범위 검사 없음!

✅ 안전: IF DColl_Loop_Item >= 1 AND DColl_Loop_Item <= 10 THEN
value := Name[DColl_Loop_Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: Name[DColl_Loop_Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF DColl_Loop_Item >= 1 AND
      DColl_Loop_Item <= 10 THEN
       value := Name[DColl_Loop_Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, DColl_Loop_Item, 10);
   value := Name[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF DColl_Loop_Item >= ARRAY_MIN AND DColl_Loop_Item <= ARRAY_MAX THEN
       value := Name[DColl_Loop_Item];
   END_IF

예시:

❌ 위험: value := Name[DColl_Loop_Item]; // 범위 검사 없음!

✅ 안전: IF DColl_Loop_Item >= 1 AND DColl_Loop_Item <= 10 THEN
value := Name[DColl_Loop_Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: Name[DColl_Loop_Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF DColl_Loop_Item >= 1 AND
      DColl_Loop_Item <= 10 THEN
       value := Name[DColl_Loop_Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, DColl_Loop_Item, 10);
   value := Name[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF DColl_Loop_Item >= ARRAY_MIN AND DColl_Loop_Item <= ARRAY_MAX THEN
       value := Name[DColl_Loop_Item];
   END_IF

예시:

❌ 위험: value := Name[DColl_Loop_Item]; // 범위 검사 없음!

✅ 안전: IF DColl_Loop_Item >= 1 AND DColl_Loop_Item <= 10 THEN
value := Name[DColl_Loop_Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: Name[DColl_Loop_Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF DColl_Loop_Item >= 1 AND
      DColl_Loop_Item <= 10 THEN
       value := Name[DColl_Loop_Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, DColl_Loop_Item, 10);
   value := Name[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF DColl_Loop_Item >= ARRAY_MIN AND DColl_Loop_Item <= ARRAY_MAX THEN
       value := Name[DColl_Loop_Item];
   END_IF

예시:

❌ 위험: value := Name[DColl_Loop_Item]; // 범위 검사 없음!

✅ 안전: IF DColl_Loop_Item >= 1 AND DColl_Loop_Item <= 10 THEN
value := Name[DColl_Loop_Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: Name[DColl_Loop_Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF DColl_Loop_Item >= 1 AND
      DColl_Loop_Item <= 10 THEN
       value := Name[DColl_Loop_Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, DColl_Loop_Item, 10);
   value := Name[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF DColl_Loop_Item >= ARRAY_MIN AND DColl_Loop_Item <= ARRAY_MAX THEN
       value := Name[DColl_Loop_Item];
   END_IF

예시:

❌ 위험: value := Name[DColl_Loop_Item]; // 범위 검사 없음!

✅ 안전: IF DColl_Loop_Item >= 1 AND DColl_Loop_Item <= 10 THEN
value := Name[DColl_Loop_Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: Name[DColl_Loop_Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF DColl_Loop_Item >= 1 AND
      DColl_Loop_Item <= 10 THEN
       value := Name[DColl_Loop_Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, DColl_Loop_Item, 10);
   value := Name[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF DColl_Loop_Item >= ARRAY_MIN AND DColl_Loop_Item <= ARRAY_MAX THEN
       value := Name[DColl_Loop_Item];
   END_IF

예시:

❌ 위험: value := Name[DColl_Loop_Item]; // 범위 검사 없음!

✅ 안전: IF DColl_Loop_Item >= 1 AND DColl_Loop_Item <= 10 THEN
value := Name[DColl_Loop_Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: Name[DColl_Loop_Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF DColl_Loop_Item >= 1 AND
      DColl_Loop_Item <= 10 THEN
       value := Name[DColl_Loop_Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, DColl_Loop_Item, 10);
   value := Name[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF DColl_Loop_Item >= ARRAY_MIN AND DColl_Loop_Item <= ARRAY_MAX THEN
       value := Name[DColl_Loop_Item];
   END_IF

예시:

❌ 위험: value := Name[DColl_Loop_Item]; // 범위 검사 없음!

✅ 안전: IF DColl_Loop_Item >= 1 AND DColl_Loop_Item <= 10 THEN
value := Name[DColl_Loop_Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: cNAME_Heater_Zone[DColl_Loop_Zone]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF DColl_Loop_Zone >= 1 AND
      DColl_Loop_Zone <= 10 THEN
       value := cNAME_Heater_Zone[DColl_Loop_Zone];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, DColl_Loop_Zone, 10);
   value := cNAME_Heater_Zone[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF DColl_Loop_Zone >= ARRAY_MIN AND DColl_Loop_Zone <= ARRAY_MAX THEN
       value := cNAME_Heater_Zone[DColl_Loop_Zone];
   END_IF

예시:

❌ 위험: value := cNAME_Heater_Zone[DColl_Loop_Zone]; // 범위 검사 없음!

✅ 안전: IF DColl_Loop_Zone >= 1 AND DColl_Loop_Zone <= 10 THEN
value := cNAME_Heater_Zone[DColl_Loop_Zone];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: LogOpen: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogOpen <> NULL THEN
       value := LogOpen^;
       // 또는 LogOpen.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogOpen');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogOpen) THEN
       value := LogOpen.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogOpen := ADR(targetVariable);
   IF LogOpen = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogOpen = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogOpen^; // NULL 체크 없음!
value := LogOpen.member; // NULL 체크 없음!

✅ 안전: IF LogOpen <> NULL THEN
value := LogOpen^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogOpen) THEN
value := LogOpen.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: LogOpen: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogOpen <> NULL THEN
       value := LogOpen^;
       // 또는 LogOpen.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogOpen');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogOpen) THEN
       value := LogOpen.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogOpen := ADR(targetVariable);
   IF LogOpen = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogOpen = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogOpen^; // NULL 체크 없음!
value := LogOpen.member; // NULL 체크 없음!

✅ 안전: IF LogOpen <> NULL THEN
value := LogOpen^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogOpen) THEN
value := LogOpen.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: LogOpen: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogOpen <> NULL THEN
       value := LogOpen^;
       // 또는 LogOpen.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogOpen');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogOpen) THEN
       value := LogOpen.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogOpen := ADR(targetVariable);
   IF LogOpen = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogOpen = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogOpen^; // NULL 체크 없음!
value := LogOpen.member; // NULL 체크 없음!

✅ 안전: IF LogOpen <> NULL THEN
value := LogOpen^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogOpen) THEN
value := LogOpen.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: LogOpen: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogOpen <> NULL THEN
       value := LogOpen^;
       // 또는 LogOpen.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogOpen');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogOpen) THEN
       value := LogOpen.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogOpen := ADR(targetVariable);
   IF LogOpen = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogOpen = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogOpen^; // NULL 체크 없음!
value := LogOpen.member; // NULL 체크 없음!

✅ 안전: IF LogOpen <> NULL THEN
value := LogOpen^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogOpen) THEN
value := LogOpen.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: LogWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogWrite <> NULL THEN
       value := LogWrite^;
       // 또는 LogWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogWrite) THEN
       value := LogWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogWrite := ADR(targetVariable);
   IF LogWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogWrite^; // NULL 체크 없음!
value := LogWrite.member; // NULL 체크 없음!

✅ 안전: IF LogWrite <> NULL THEN
value := LogWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogWrite) THEN
value := LogWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: LogWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogWrite <> NULL THEN
       value := LogWrite^;
       // 또는 LogWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogWrite) THEN
       value := LogWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogWrite := ADR(targetVariable);
   IF LogWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogWrite^; // NULL 체크 없음!
value := LogWrite.member; // NULL 체크 없음!

✅ 안전: IF LogWrite <> NULL THEN
value := LogWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogWrite) THEN
value := LogWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: LogWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogWrite <> NULL THEN
       value := LogWrite^;
       // 또는 LogWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogWrite) THEN
       value := LogWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogWrite := ADR(targetVariable);
   IF LogWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogWrite^; // NULL 체크 없음!
value := LogWrite.member; // NULL 체크 없음!

✅ 안전: IF LogWrite <> NULL THEN
value := LogWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogWrite) THEN
value := LogWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: LogClose: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogClose <> NULL THEN
       value := LogClose^;
       // 또는 LogClose.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogClose');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogClose) THEN
       value := LogClose.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogClose := ADR(targetVariable);
   IF LogClose = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogClose = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogClose^; // NULL 체크 없음!
value := LogClose.member; // NULL 체크 없음!

✅ 안전: IF LogClose <> NULL THEN
value := LogClose^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogClose) THEN
value := LogClose.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: LogClose: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogClose <> NULL THEN
       value := LogClose^;
       // 또는 LogClose.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogClose');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogClose) THEN
       value := LogClose.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogClose := ADR(targetVariable);
   IF LogClose = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogClose = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogClose^; // NULL 체크 없음!
value := LogClose.member; // NULL 체크 없음!

✅ 안전: IF LogClose <> NULL THEN
value := LogClose^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogClose) THEN
value := LogClose.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: LogClose: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogClose <> NULL THEN
       value := LogClose^;
       // 또는 LogClose.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogClose');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogClose) THEN
       value := LogClose.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogClose := ADR(targetVariable);
   IF LogClose = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogClose = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogClose^; // NULL 체크 없음!
value := LogClose.member; // NULL 체크 없음!

✅ 안전: IF LogClose <> NULL THEN
value := LogClose^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogClose) THEN
value := LogClose.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: fbDate_Log: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF fbDate_Log <> NULL THEN
       value := fbDate_Log^;
       // 또는 fbDate_Log.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: fbDate_Log');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(fbDate_Log) THEN
       value := fbDate_Log.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   fbDate_Log := ADR(targetVariable);
   IF fbDate_Log = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF fbDate_Log = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := fbDate_Log^; // NULL 체크 없음!
value := fbDate_Log.member; // NULL 체크 없음!

✅ 안전: IF fbDate_Log <> NULL THEN
value := fbDate_Log^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(fbDate_Log) THEN
value := fbDate_Log.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: Log_Dir_CTC: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Log_Dir_CTC <> NULL THEN
       value := Log_Dir_CTC^;
       // 또는 Log_Dir_CTC.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Log_Dir_CTC');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Log_Dir_CTC) THEN
       value := Log_Dir_CTC.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Log_Dir_CTC := ADR(targetVariable);
   IF Log_Dir_CTC = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Log_Dir_CTC = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Log_Dir_CTC^; // NULL 체크 없음!
value := Log_Dir_CTC.member; // NULL 체크 없음!

✅ 안전: IF Log_Dir_CTC <> NULL THEN
value := Log_Dir_CTC^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Log_Dir_CTC) THEN
value := Log_Dir_CTC.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: Log_Dir_CTC: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Log_Dir_CTC <> NULL THEN
       value := Log_Dir_CTC^;
       // 또는 Log_Dir_CTC.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Log_Dir_CTC');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Log_Dir_CTC) THEN
       value := Log_Dir_CTC.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Log_Dir_CTC := ADR(targetVariable);
   IF Log_Dir_CTC = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Log_Dir_CTC = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Log_Dir_CTC^; // NULL 체크 없음!
value := Log_Dir_CTC.member; // NULL 체크 없음!

✅ 안전: IF Log_Dir_CTC <> NULL THEN
value := Log_Dir_CTC^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Log_Dir_CTC) THEN
value := Log_Dir_CTC.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: LOG_Event: 203줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: LOG_Event = 203줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: Msg = Event_Log_Msg: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Msg - Event_Log_Msg) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Msg >= (Event_Log_Msg - 1.0E-6) AND
      Msg <= (Event_Log_Msg + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Msg >= Event_Log_Msg THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Msg * 10.0);
   intTarget := REAL_TO_DINT(Event_Log_Msg * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Msg = Event_Log_Msg THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Msg - Event_Log_Msg) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: TRUE = LogOpen.bBusy: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogOpen.bBusy) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogOpen.bBusy - 1.0E-6) AND
      TRUE <= (LogOpen.bBusy + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogOpen.bBusy THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogOpen.bBusy * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogOpen.bBusy THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogOpen.bBusy) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: TRUE = LogOpen.bError: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogOpen.bError) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogOpen.bError - 1.0E-6) AND
      TRUE <= (LogOpen.bError + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogOpen.bError THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogOpen.bError * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogOpen.bError THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogOpen.bError) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: TRUE = LogWrite.bBusy: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogWrite.bBusy) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogWrite.bBusy - 1.0E-6) AND
      TRUE <= (LogWrite.bBusy + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogWrite.bBusy THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogWrite.bBusy * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogWrite.bBusy THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogWrite.bBusy) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: TRUE = LogWrite.bError: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogWrite.bError) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogWrite.bError - 1.0E-6) AND
      TRUE <= (LogWrite.bError + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogWrite.bError THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogWrite.bError * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogWrite.bError THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogWrite.bError) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: TRUE = LogClose.bBusy: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogClose.bBusy) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogClose.bBusy - 1.0E-6) AND
      TRUE <= (LogClose.bBusy + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogClose.bBusy THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogClose.bBusy * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogClose.bBusy THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogClose.bBusy) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: TRUE = LogClose.bError: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogClose.bError) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogClose.bError - 1.0E-6) AND
      TRUE <= (LogClose.bError + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogClose.bError THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogClose.bError * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogClose.bError THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogClose.bError) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: LogHandle <> 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(LogHandle - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF LogHandle >= (0 - 1.0E-6) AND
      LogHandle <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF LogHandle >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(LogHandle * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF LogHandle = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(LogHandle - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: Boot = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Boot - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Boot >= (FALSE - 1.0E-6) AND
      Boot <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Boot >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Boot * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Boot = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Boot - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: systemTime: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF systemTime <> NULL THEN
       value := systemTime^;
       // 또는 systemTime.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: systemTime');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(systemTime) THEN
       value := systemTime.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   systemTime := ADR(targetVariable);
   IF systemTime = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF systemTime = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := systemTime^; // NULL 체크 없음!
value := systemTime.member; // NULL 체크 없음!

✅ 안전: IF systemTime <> NULL THEN
value := systemTime^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(systemTime) THEN
value := systemTime.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: Log_Dir_MARS: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Log_Dir_MARS <> NULL THEN
       value := Log_Dir_MARS^;
       // 또는 Log_Dir_MARS.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Log_Dir_MARS');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Log_Dir_MARS) THEN
       value := Log_Dir_MARS.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Log_Dir_MARS := ADR(targetVariable);
   IF Log_Dir_MARS = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Log_Dir_MARS = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Log_Dir_MARS^; // NULL 체크 없음!
value := Log_Dir_MARS.member; // NULL 체크 없음!

✅ 안전: IF Log_Dir_MARS <> NULL THEN
value := Log_Dir_MARS^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Log_Dir_MARS) THEN
value := Log_Dir_MARS.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: systemTime: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF systemTime <> NULL THEN
       value := systemTime^;
       // 또는 systemTime.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: systemTime');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(systemTime) THEN
       value := systemTime.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   systemTime := ADR(targetVariable);
   IF systemTime = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF systemTime = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := systemTime^; // NULL 체크 없음!
value := systemTime.member; // NULL 체크 없음!

✅ 안전: IF systemTime <> NULL THEN
value := systemTime^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(systemTime) THEN
value := systemTime.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: systemTime: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF systemTime <> NULL THEN
       value := systemTime^;
       // 또는 systemTime.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: systemTime');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(systemTime) THEN
       value := systemTime.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   systemTime := ADR(targetVariable);
   IF systemTime = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF systemTime = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := systemTime^; // NULL 체크 없음!
value := systemTime.member; // NULL 체크 없음!

✅ 안전: IF systemTime <> NULL THEN
value := systemTime^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(systemTime) THEN
value := systemTime.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: systemTime: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF systemTime <> NULL THEN
       value := systemTime^;
       // 또는 systemTime.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: systemTime');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(systemTime) THEN
       value := systemTime.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   systemTime := ADR(targetVariable);
   IF systemTime = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF systemTime = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := systemTime^; // NULL 체크 없음!
value := systemTime.member; // NULL 체크 없음!

✅ 안전: IF systemTime <> NULL THEN
value := systemTime^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(systemTime) THEN
value := systemTime.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: MAIN: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF MAIN <> NULL THEN
       value := MAIN^;
       // 또는 MAIN.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: MAIN');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(MAIN) THEN
       value := MAIN.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   MAIN := ADR(targetVariable);
   IF MAIN = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF MAIN = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := MAIN^; // NULL 체크 없음!
value := MAIN.member; // NULL 체크 없음!

✅ 안전: IF MAIN <> NULL THEN
value := MAIN^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(MAIN) THEN
value := MAIN.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: systemTime: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF systemTime <> NULL THEN
       value := systemTime^;
       // 또는 systemTime.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: systemTime');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(systemTime) THEN
       value := systemTime.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   systemTime := ADR(targetVariable);
   IF systemTime = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF systemTime = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := systemTime^; // NULL 체크 없음!
value := systemTime.member; // NULL 체크 없음!

✅ 안전: IF systemTime <> NULL THEN
value := systemTime^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(systemTime) THEN
value := systemTime.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: LOG_Mars: 396줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: LOG_Mars = 396줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: Boot = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Boot - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Boot >= (FALSE - 1.0E-6) AND
      Boot <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Boot >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Boot * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Boot = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Boot - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: Boot = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Boot - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Boot >= (FALSE - 1.0E-6) AND
      Boot <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Boot >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Boot * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Boot = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Boot - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: TRUE = Log_Dir_MARS.bBusy: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - Log_Dir_MARS.bBusy) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (Log_Dir_MARS.bBusy - 1.0E-6) AND
      TRUE <= (Log_Dir_MARS.bBusy + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= Log_Dir_MARS.bBusy THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(Log_Dir_MARS.bBusy * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = Log_Dir_MARS.bBusy THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - Log_Dir_MARS.bBusy) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: ARRAY[1..4]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..4 >= 1 AND
      1..4 <= 10 THEN
       value := ARRAY[1..4];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..4, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..4 >= ARRAY_MIN AND 1..4 <= ARRAY_MAX THEN
       value := ARRAY[1..4];
   END_IF

예시:

❌ 위험: value := ARRAY[1..4]; // 범위 검사 없음!

✅ 안전: IF 1..4 >= 1 AND 1..4 <= 10 THEN
value := ARRAY[1..4];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: ARRAY[1..4]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..4 >= 1 AND
      1..4 <= 10 THEN
       value := ARRAY[1..4];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..4, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..4 >= ARRAY_MIN AND 1..4 <= ARRAY_MAX THEN
       value := ARRAY[1..4];
   END_IF

예시:

❌ 위험: value := ARRAY[1..4]; // 범위 검사 없음!

✅ 안전: IF 1..4 >= 1 AND 1..4 <= 10 THEN
value := ARRAY[1..4];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: ARRAY[1..cMAX_Mars_Info]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Mars_Info >= 1 AND
      1..cMAX_Mars_Info <= 10 THEN
       value := ARRAY[1..cMAX_Mars_Info];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Mars_Info, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Mars_Info >= ARRAY_MIN AND 1..cMAX_Mars_Info <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Mars_Info];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Mars_Info]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Mars_Info >= 1 AND 1..cMAX_Mars_Info <= 10 THEN
value := ARRAY[1..cMAX_Mars_Info];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: ARRAY[1..8]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..8 >= 1 AND
      1..8 <= 10 THEN
       value := ARRAY[1..8];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..8, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..8 >= ARRAY_MIN AND 1..8 <= ARRAY_MAX THEN
       value := ARRAY[1..8];
   END_IF

예시:

❌ 위험: value := ARRAY[1..8]; // 범위 검사 없음!

✅ 안전: IF 1..8 >= 1 AND 1..8 <= 10 THEN
value := ARRAY[1..8];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: ARRAY[1..cMAX_Mars_Log_Buffer]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Mars_Log_Buffer >= 1 AND
      1..cMAX_Mars_Log_Buffer <= 10 THEN
       value := ARRAY[1..cMAX_Mars_Log_Buffer];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Mars_Log_Buffer, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Mars_Log_Buffer >= ARRAY_MIN AND 1..cMAX_Mars_Log_Buffer <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Mars_Log_Buffer];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Mars_Log_Buffer]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Mars_Log_Buffer >= 1 AND 1..cMAX_Mars_Log_Buffer <= 10 THEN
value := ARRAY[1..cMAX_Mars_Log_Buffer];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: ARRAY[1..cMAX_Log_Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Log_Item >= 1 AND
      1..cMAX_Log_Item <= 10 THEN
       value := ARRAY[1..cMAX_Log_Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Log_Item, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Log_Item >= ARRAY_MIN AND 1..cMAX_Log_Item <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Log_Item];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Log_Item]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Log_Item >= 1 AND 1..cMAX_Log_Item <= 10 THEN
value := ARRAY[1..cMAX_Log_Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: ARRAY[1..cMAX_Log_Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Log_Item >= 1 AND
      1..cMAX_Log_Item <= 10 THEN
       value := ARRAY[1..cMAX_Log_Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Log_Item, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Log_Item >= ARRAY_MIN AND 1..cMAX_Log_Item <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Log_Item];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Log_Item]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Log_Item >= 1 AND 1..cMAX_Log_Item <= 10 THEN
value := ARRAY[1..cMAX_Log_Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: LogOpen: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogOpen <> NULL THEN
       value := LogOpen^;
       // 또는 LogOpen.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogOpen');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogOpen) THEN
       value := LogOpen.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogOpen := ADR(targetVariable);
   IF LogOpen = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogOpen = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogOpen^; // NULL 체크 없음!
value := LogOpen.member; // NULL 체크 없음!

✅ 안전: IF LogOpen <> NULL THEN
value := LogOpen^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogOpen) THEN
value := LogOpen.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: LogOpen: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogOpen <> NULL THEN
       value := LogOpen^;
       // 또는 LogOpen.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogOpen');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogOpen) THEN
       value := LogOpen.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogOpen := ADR(targetVariable);
   IF LogOpen = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogOpen = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogOpen^; // NULL 체크 없음!
value := LogOpen.member; // NULL 체크 없음!

✅ 안전: IF LogOpen <> NULL THEN
value := LogOpen^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogOpen) THEN
value := LogOpen.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: LogOpen: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogOpen <> NULL THEN
       value := LogOpen^;
       // 또는 LogOpen.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogOpen');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogOpen) THEN
       value := LogOpen.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogOpen := ADR(targetVariable);
   IF LogOpen = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogOpen = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogOpen^; // NULL 체크 없음!
value := LogOpen.member; // NULL 체크 없음!

✅ 안전: IF LogOpen <> NULL THEN
value := LogOpen^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogOpen) THEN
value := LogOpen.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: LogOpen: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogOpen <> NULL THEN
       value := LogOpen^;
       // 또는 LogOpen.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogOpen');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogOpen) THEN
       value := LogOpen.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogOpen := ADR(targetVariable);
   IF LogOpen = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogOpen = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogOpen^; // NULL 체크 없음!
value := LogOpen.member; // NULL 체크 없음!

✅ 안전: IF LogOpen <> NULL THEN
value := LogOpen^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogOpen) THEN
value := LogOpen.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: LogPuts: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogPuts <> NULL THEN
       value := LogPuts^;
       // 또는 LogPuts.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogPuts');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogPuts) THEN
       value := LogPuts.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogPuts := ADR(targetVariable);
   IF LogPuts = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogPuts = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogPuts^; // NULL 체크 없음!
value := LogPuts.member; // NULL 체크 없음!

✅ 안전: IF LogPuts <> NULL THEN
value := LogPuts^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogPuts) THEN
value := LogPuts.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: LogPuts: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogPuts <> NULL THEN
       value := LogPuts^;
       // 또는 LogPuts.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogPuts');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogPuts) THEN
       value := LogPuts.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogPuts := ADR(targetVariable);
   IF LogPuts = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogPuts = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogPuts^; // NULL 체크 없음!
value := LogPuts.member; // NULL 체크 없음!

✅ 안전: IF LogPuts <> NULL THEN
value := LogPuts^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogPuts) THEN
value := LogPuts.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: LogPuts: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogPuts <> NULL THEN
       value := LogPuts^;
       // 또는 LogPuts.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogPuts');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogPuts) THEN
       value := LogPuts.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogPuts := ADR(targetVariable);
   IF LogPuts = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogPuts = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogPuts^; // NULL 체크 없음!
value := LogPuts.member; // NULL 체크 없음!

✅ 안전: IF LogPuts <> NULL THEN
value := LogPuts^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogPuts) THEN
value := LogPuts.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: LogPuts: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogPuts <> NULL THEN
       value := LogPuts^;
       // 또는 LogPuts.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogPuts');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogPuts) THEN
       value := LogPuts.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogPuts := ADR(targetVariable);
   IF LogPuts = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogPuts = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogPuts^; // NULL 체크 없음!
value := LogPuts.member; // NULL 체크 없음!

✅ 안전: IF LogPuts <> NULL THEN
value := LogPuts^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogPuts) THEN
value := LogPuts.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: LogPuts: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogPuts <> NULL THEN
       value := LogPuts^;
       // 또는 LogPuts.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogPuts');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogPuts) THEN
       value := LogPuts.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogPuts := ADR(targetVariable);
   IF LogPuts = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogPuts = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogPuts^; // NULL 체크 없음!
value := LogPuts.member; // NULL 체크 없음!

✅ 안전: IF LogPuts <> NULL THEN
value := LogPuts^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogPuts) THEN
value := LogPuts.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: LogClose: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogClose <> NULL THEN
       value := LogClose^;
       // 또는 LogClose.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogClose');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogClose) THEN
       value := LogClose.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogClose := ADR(targetVariable);
   IF LogClose = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogClose = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogClose^; // NULL 체크 없음!
value := LogClose.member; // NULL 체크 없음!

✅ 안전: IF LogClose <> NULL THEN
value := LogClose^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogClose) THEN
value := LogClose.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: LogClose: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogClose <> NULL THEN
       value := LogClose^;
       // 또는 LogClose.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogClose');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogClose) THEN
       value := LogClose.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogClose := ADR(targetVariable);
   IF LogClose = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogClose = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogClose^; // NULL 체크 없음!
value := LogClose.member; // NULL 체크 없음!

✅ 안전: IF LogClose <> NULL THEN
value := LogClose^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogClose) THEN
value := LogClose.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: LogClose: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogClose <> NULL THEN
       value := LogClose^;
       // 또는 LogClose.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogClose');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogClose) THEN
       value := LogClose.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogClose := ADR(targetVariable);
   IF LogClose = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogClose = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogClose^; // NULL 체크 없음!
value := LogClose.member; // NULL 체크 없음!

✅ 안전: IF LogClose <> NULL THEN
value := LogClose^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogClose) THEN
value := LogClose.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: LOG_Parameter: 139줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: LOG_Parameter = 139줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: DX_INF_State_Process <> eProcess_Processing: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Process >= (eProcess_Processing - 1.0E-6) AND
      DX_INF_State_Process <= (eProcess_Processing + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Process >= eProcess_Processing THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Process * 10.0);
   intTarget := REAL_TO_DINT(eProcess_Processing * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Process = eProcess_Processing THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: FALSE = DX_INF_Para_Log: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(FALSE - DX_INF_Para_Log) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF FALSE >= (DX_INF_Para_Log - 1.0E-6) AND
      FALSE <= (DX_INF_Para_Log + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF FALSE >= DX_INF_Para_Log THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(FALSE * 10.0);
   intTarget := REAL_TO_DINT(DX_INF_Para_Log * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF FALSE = DX_INF_Para_Log THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(FALSE - DX_INF_Para_Log) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: TRUE = LogOpen.bBusy: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogOpen.bBusy) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogOpen.bBusy - 1.0E-6) AND
      TRUE <= (LogOpen.bBusy + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogOpen.bBusy THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogOpen.bBusy * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogOpen.bBusy THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogOpen.bBusy) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: TRUE = LogOpen.bError: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogOpen.bError) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogOpen.bError - 1.0E-6) AND
      TRUE <= (LogOpen.bError + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogOpen.bError THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogOpen.bError * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogOpen.bError THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogOpen.bError) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: TRUE = LogPuts.bBusy: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogPuts.bBusy) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogPuts.bBusy - 1.0E-6) AND
      TRUE <= (LogPuts.bBusy + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogPuts.bBusy THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogPuts.bBusy * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogPuts.bBusy THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogPuts.bBusy) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: TRUE = LogPuts.bBusy: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogPuts.bBusy) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogPuts.bBusy - 1.0E-6) AND
      TRUE <= (LogPuts.bBusy + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogPuts.bBusy THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogPuts.bBusy * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogPuts.bBusy THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogPuts.bBusy) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: TRUE = LogPuts.bBusy: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogPuts.bBusy) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogPuts.bBusy - 1.0E-6) AND
      TRUE <= (LogPuts.bBusy + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogPuts.bBusy THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogPuts.bBusy * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogPuts.bBusy THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogPuts.bBusy) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: TRUE = LogPuts.bError: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogPuts.bError) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogPuts.bError - 1.0E-6) AND
      TRUE <= (LogPuts.bError + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogPuts.bError THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogPuts.bError * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogPuts.bError THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogPuts.bError) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: TRUE = LogClose.bBusy: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogClose.bBusy) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogClose.bBusy - 1.0E-6) AND
      TRUE <= (LogClose.bBusy + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogClose.bBusy THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogClose.bBusy * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogClose.bBusy THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogClose.bBusy) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: TRUE = LogClose.bError: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogClose.bError) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogClose.bError - 1.0E-6) AND
      TRUE <= (LogClose.bError + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogClose.bError THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogClose.bError * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogClose.bError THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogClose.bError) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: LogHandle <> 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(LogHandle - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF LogHandle >= (0 - 1.0E-6) AND
      LogHandle <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF LogHandle >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(LogHandle * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF LogHandle = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(LogHandle - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: Para_Log_Data[Item_Count]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Item_Count >= 1 AND
      Item_Count <= 10 THEN
       value := Para_Log_Data[Item_Count];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Item_Count, 10);
   value := Para_Log_Data[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Item_Count >= ARRAY_MIN AND Item_Count <= ARRAY_MAX THEN
       value := Para_Log_Data[Item_Count];
   END_IF

예시:

❌ 위험: value := Para_Log_Data[Item_Count]; // 범위 검사 없음!

✅ 안전: IF Item_Count >= 1 AND Item_Count <= 10 THEN
value := Para_Log_Data[Item_Count];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: LogOpen: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogOpen <> NULL THEN
       value := LogOpen^;
       // 또는 LogOpen.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogOpen');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogOpen) THEN
       value := LogOpen.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogOpen := ADR(targetVariable);
   IF LogOpen = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogOpen = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogOpen^; // NULL 체크 없음!
value := LogOpen.member; // NULL 체크 없음!

✅ 안전: IF LogOpen <> NULL THEN
value := LogOpen^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogOpen) THEN
value := LogOpen.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: LogOpen: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogOpen <> NULL THEN
       value := LogOpen^;
       // 또는 LogOpen.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogOpen');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogOpen) THEN
       value := LogOpen.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogOpen := ADR(targetVariable);
   IF LogOpen = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogOpen = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogOpen^; // NULL 체크 없음!
value := LogOpen.member; // NULL 체크 없음!

✅ 안전: IF LogOpen <> NULL THEN
value := LogOpen^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogOpen) THEN
value := LogOpen.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: LogOpen: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogOpen <> NULL THEN
       value := LogOpen^;
       // 또는 LogOpen.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogOpen');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogOpen) THEN
       value := LogOpen.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogOpen := ADR(targetVariable);
   IF LogOpen = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogOpen = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogOpen^; // NULL 체크 없음!
value := LogOpen.member; // NULL 체크 없음!

✅ 안전: IF LogOpen <> NULL THEN
value := LogOpen^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogOpen) THEN
value := LogOpen.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: LogOpen: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogOpen <> NULL THEN
       value := LogOpen^;
       // 또는 LogOpen.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogOpen');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogOpen) THEN
       value := LogOpen.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogOpen := ADR(targetVariable);
   IF LogOpen = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogOpen = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogOpen^; // NULL 체크 없음!
value := LogOpen.member; // NULL 체크 없음!

✅ 안전: IF LogOpen <> NULL THEN
value := LogOpen^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogOpen) THEN
value := LogOpen.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: LogWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogWrite <> NULL THEN
       value := LogWrite^;
       // 또는 LogWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogWrite) THEN
       value := LogWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogWrite := ADR(targetVariable);
   IF LogWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogWrite^; // NULL 체크 없음!
value := LogWrite.member; // NULL 체크 없음!

✅ 안전: IF LogWrite <> NULL THEN
value := LogWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogWrite) THEN
value := LogWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: LogWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogWrite <> NULL THEN
       value := LogWrite^;
       // 또는 LogWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogWrite) THEN
       value := LogWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogWrite := ADR(targetVariable);
   IF LogWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogWrite^; // NULL 체크 없음!
value := LogWrite.member; // NULL 체크 없음!

✅ 안전: IF LogWrite <> NULL THEN
value := LogWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogWrite) THEN
value := LogWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: LogWrite: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogWrite <> NULL THEN
       value := LogWrite^;
       // 또는 LogWrite.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogWrite');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogWrite) THEN
       value := LogWrite.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogWrite := ADR(targetVariable);
   IF LogWrite = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogWrite = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogWrite^; // NULL 체크 없음!
value := LogWrite.member; // NULL 체크 없음!

✅ 안전: IF LogWrite <> NULL THEN
value := LogWrite^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogWrite) THEN
value := LogWrite.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: LogPuts: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogPuts <> NULL THEN
       value := LogPuts^;
       // 또는 LogPuts.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogPuts');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogPuts) THEN
       value := LogPuts.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogPuts := ADR(targetVariable);
   IF LogPuts = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogPuts = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogPuts^; // NULL 체크 없음!
value := LogPuts.member; // NULL 체크 없음!

✅ 안전: IF LogPuts <> NULL THEN
value := LogPuts^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogPuts) THEN
value := LogPuts.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: LogPuts: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF LogPuts <> NULL THEN
       value := LogPuts^;
       // 또는 LogPuts.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: LogPuts');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(LogPuts) THEN
       value := LogPuts.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   LogPuts := ADR(targetVariable);
   IF LogPuts = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF LogPuts = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := LogPuts^; // NULL 체크 없음!
value := LogPuts.member; // NULL 체크 없음!

✅ 안전: IF LogPuts <> NULL THEN
value := LogPuts^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(LogPuts) THEN
value := LogPuts.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: LOG_Process: 162줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: LOG_Process = 162줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: DO_ManualLog_Command = eTune_Start: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DO_ManualLog_Command - eTune_Start) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DO_ManualLog_Command >= (eTune_Start - 1.0E-6) AND
      DO_ManualLog_Command <= (eTune_Start + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DO_ManualLog_Command >= eTune_Start THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DO_ManualLog_Command * 10.0);
   intTarget := REAL_TO_DINT(eTune_Start * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DO_ManualLog_Command = eTune_Start THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DO_ManualLog_Command - eTune_Start) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: TRUE = LogOpen.bBusy: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogOpen.bBusy) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogOpen.bBusy - 1.0E-6) AND
      TRUE <= (LogOpen.bBusy + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogOpen.bBusy THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogOpen.bBusy * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogOpen.bBusy THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogOpen.bBusy) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: TRUE = LogOpen.bError: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogOpen.bError) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogOpen.bError - 1.0E-6) AND
      TRUE <= (LogOpen.bError + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogOpen.bError THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogOpen.bError * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogOpen.bError THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogOpen.bError) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: TRUE = LogWrite.bBusy: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogWrite.bBusy) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogWrite.bBusy - 1.0E-6) AND
      TRUE <= (LogWrite.bBusy + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogWrite.bBusy THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogWrite.bBusy * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogWrite.bBusy THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogWrite.bBusy) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: TRUE = LogWrite.bError: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogWrite.bError) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogWrite.bError - 1.0E-6) AND
      TRUE <= (LogWrite.bError + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogWrite.bError THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogWrite.bError * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogWrite.bError THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogWrite.bError) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: TRUE = LogPuts.bBusy: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogPuts.bBusy) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogPuts.bBusy - 1.0E-6) AND
      TRUE <= (LogPuts.bBusy + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogPuts.bBusy THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogPuts.bBusy * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogPuts.bBusy THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogPuts.bBusy) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: TRUE = LogPuts.bBusy: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - LogPuts.bBusy) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (LogPuts.bBusy - 1.0E-6) AND
      TRUE <= (LogPuts.bBusy + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= LogPuts.bBusy THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(LogPuts.bBusy * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = LogPuts.bBusy THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - LogPuts.bBusy) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: TRUE = L: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(TRUE - L) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF TRUE >= (L - 1.0E-6) AND
      TRUE <= (L + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF TRUE >= L THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(TRUE * 10.0);
   intTarget := REAL_TO_DINT(L * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF TRUE = L THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(TRUE - L) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: ARRAY[1..cMAX_Log_Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Log_Item >= 1 AND
      1..cMAX_Log_Item <= 10 THEN
       value := ARRAY[1..cMAX_Log_Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Log_Item, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Log_Item >= ARRAY_MIN AND 1..cMAX_Log_Item <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Log_Item];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Log_Item]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Log_Item >= 1 AND 1..cMAX_Log_Item <= 10 THEN
value := ARRAY[1..cMAX_Log_Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: ARRAY[1..cMAX_Log_Item]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Log_Item >= 1 AND
      1..cMAX_Log_Item <= 10 THEN
       value := ARRAY[1..cMAX_Log_Item];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Log_Item, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Log_Item >= ARRAY_MIN AND 1..cMAX_Log_Item <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Log_Item];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Log_Item]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Log_Item >= 1 AND 1..cMAX_Log_Item <= 10 THEN
value := ARRAY[1..cMAX_Log_Item];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: ARRAY[1..cMAX_Log_Buffer]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Log_Buffer >= 1 AND
      1..cMAX_Log_Buffer <= 10 THEN
       value := ARRAY[1..cMAX_Log_Buffer];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Log_Buffer, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Log_Buffer >= ARRAY_MIN AND 1..cMAX_Log_Buffer <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Log_Buffer];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Log_Buffer]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Log_Buffer >= 1 AND 1..cMAX_Log_Buffer <= 10 THEN
value := ARRAY[1..cMAX_Log_Buffer];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: Msg[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := Msg[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := Msg[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := Msg[Loop];
   END_IF

예시:

❌ 위험: value := Msg[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := Msg[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: Log_Title[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := Log_Title[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := Log_Title[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := Log_Title[Loop];
   END_IF

예시:

❌ 위험: value := Log_Title[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := Log_Title[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: Log_Title[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := Log_Title[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := Log_Title[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := Log_Title[Loop];
   END_IF

예시:

❌ 위험: value := Log_Title[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := Log_Title[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: Msg[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := Msg[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := Msg[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := Msg[Loop];
   END_IF

예시:

❌ 위험: value := Msg[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := Msg[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: Msg[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := Msg[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := Msg[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := Msg[Loop];
   END_IF

예시:

❌ 위험: value := Msg[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := Msg[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: Msg[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := Msg[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := Msg[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := Msg[Loop];
   END_IF

예시:

❌ 위험: value := Msg[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := Msg[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Alarm.TcPOU:1

설명: pAlarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF pAlarm <> NULL THEN
       value := pAlarm^;
       // 또는 pAlarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: pAlarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(pAlarm) THEN
       value := pAlarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   pAlarm := ADR(targetVariable);
   IF pAlarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF pAlarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := pAlarm^; // NULL 체크 없음!
value := pAlarm.member; // NULL 체크 없음!

✅ 안전: IF pAlarm <> NULL THEN
value := pAlarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(pAlarm) THEN
value := pAlarm.member;
END_IF
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Alarm.TcPOU:1

설명: AX_INF_AlarmClear = cAlarmAllClear: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(AX_INF_AlarmClear - cAlarmAllClear) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF AX_INF_AlarmClear >= (cAlarmAllClear - 1.0E-6) AND
      AX_INF_AlarmClear <= (cAlarmAllClear + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF AX_INF_AlarmClear >= cAlarmAllClear THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(AX_INF_AlarmClear * 10.0);
   intTarget := REAL_TO_DINT(cAlarmAllClear * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF AX_INF_AlarmClear = cAlarmAllClear THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(AX_INF_AlarmClear - cAlarmAllClear) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Alarm.TcPOU:1

설명: 0 = AX_INF_AlarmClear: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(0 - AX_INF_AlarmClear) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF 0 >= (AX_INF_AlarmClear - 1.0E-6) AND
      0 <= (AX_INF_AlarmClear + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF 0 >= AX_INF_AlarmClear THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(0 * 10.0);
   intTarget := REAL_TO_DINT(AX_INF_AlarmClear * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF 0 = AX_INF_AlarmClear THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(0 - AX_INF_AlarmClear) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Alarm.TcPOU:1

설명: fbAlarm[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := fbAlarm[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := fbAlarm[Loop];
   END_IF

예시:

❌ 위험: value := fbAlarm[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := fbAlarm[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Alarm.TcPOU:1

설명: fbAlarm[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := fbAlarm[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := fbAlarm[Loop];
   END_IF

예시:

❌ 위험: value := fbAlarm[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := fbAlarm[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Alarm.TcPOU:1

설명: fbAlarm[AX_INF_AlarmClear]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF AX_INF_AlarmClear >= 1 AND
      AX_INF_AlarmClear <= 10 THEN
       value := fbAlarm[AX_INF_AlarmClear];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, AX_INF_AlarmClear, 10);
   value := fbAlarm[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF AX_INF_AlarmClear >= ARRAY_MIN AND AX_INF_AlarmClear <= ARRAY_MAX THEN
       value := fbAlarm[AX_INF_AlarmClear];
   END_IF

예시:

❌ 위험: value := fbAlarm[AX_INF_AlarmClear]; // 범위 검사 없음!

✅ 안전: IF AX_INF_AlarmClear >= 1 AND AX_INF_AlarmClear <= 10 THEN
value := fbAlarm[AX_INF_AlarmClear];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:1

설명: Log_Time: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Log_Time <> NULL THEN
       value := Log_Time^;
       // 또는 Log_Time.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Log_Time');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Log_Time) THEN
       value := Log_Time.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Log_Time := ADR(targetVariable);
   IF Log_Time = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Log_Time = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Log_Time^; // NULL 체크 없음!
value := Log_Time.member; // NULL 체크 없음!

✅ 안전: IF Log_Time <> NULL THEN
value := Log_Time^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Log_Time) THEN
value := Log_Time.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:1

설명: SYS_LV_Log: 1493줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SYS_LV_Log = 1493줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:1

설명: LV_Log_Start_Trig = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(LV_Log_Start_Trig - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF LV_Log_Start_Trig >= (TRUE - 1.0E-6) AND
      LV_Log_Start_Trig <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF LV_Log_Start_Trig >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(LV_Log_Start_Trig * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF LV_Log_Start_Trig = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(LV_Log_Start_Trig - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:1

설명: LV_Log_Title_Trig = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(LV_Log_Title_Trig - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF LV_Log_Title_Trig >= (TRUE - 1.0E-6) AND
      LV_Log_Title_Trig <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF LV_Log_Title_Trig >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(LV_Log_Title_Trig * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF LV_Log_Title_Trig = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(LV_Log_Title_Trig - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:1

설명: ARRAY[1..cMAX_Log_LV_Msg_Sum]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF 1..cMAX_Log_LV_Msg_Sum >= 1 AND
      1..cMAX_Log_LV_Msg_Sum <= 10 THEN
       value := ARRAY[1..cMAX_Log_LV_Msg_Sum];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, 1..cMAX_Log_LV_Msg_Sum, 10);
   value := ARRAY[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF 1..cMAX_Log_LV_Msg_Sum >= ARRAY_MIN AND 1..cMAX_Log_LV_Msg_Sum <= ARRAY_MAX THEN
       value := ARRAY[1..cMAX_Log_LV_Msg_Sum];
   END_IF

예시:

❌ 위험: value := ARRAY[1..cMAX_Log_LV_Msg_Sum]; // 범위 검사 없음!

✅ 안전: IF 1..cMAX_Log_LV_Msg_Sum >= 1 AND 1..cMAX_Log_LV_Msg_Sum <= 10 THEN
value := ARRAY[1..cMAX_Log_LV_Msg_Sum];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:1

설명: Log_LV_Title[(5 * (Loop - 1)) + SumLoop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF (5 * (Loop - 1)) + SumLoop >= 1 AND
      (5 * (Loop - 1)) + SumLoop <= 10 THEN
       value := Log_LV_Title[(5 * (Loop - 1)) + SumLoop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, (5 * (Loop - 1)) + SumLoop, 10);
   value := Log_LV_Title[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF (5 * (Loop - 1)) + SumLoop >= ARRAY_MIN AND (5 * (Loop - 1)) + SumLoop <= ARRAY_MAX THEN
       value := Log_LV_Title[(5 * (Loop - 1)) + SumLoop];
   END_IF

예시:

❌ 위험: value := Log_LV_Title[(5 * (Loop - 1)) + SumLoop]; // 범위 검사 없음!

✅ 안전: IF (5 * (Loop - 1)) + SumLoop >= 1 AND (5 * (Loop - 1)) + SumLoop <= 10 THEN
value := Log_LV_Title[(5 * (Loop - 1)) + SumLoop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:1

설명: LV_Msg_Sum[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := LV_Msg_Sum[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := LV_Msg_Sum[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := LV_Msg_Sum[Loop];
   END_IF

예시:

❌ 위험: value := LV_Msg_Sum[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := LV_Msg_Sum[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:1

설명: LV_Msg_Sum[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := LV_Msg_Sum[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := LV_Msg_Sum[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := LV_Msg_Sum[Loop];
   END_IF

예시:

❌ 위험: value := LV_Msg_Sum[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := LV_Msg_Sum[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:1

설명: Log_LV_Title[(5 * (Loop - 1)) + SumLoop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF (5 * (Loop - 1)) + SumLoop >= 1 AND
      (5 * (Loop - 1)) + SumLoop <= 10 THEN
       value := Log_LV_Title[(5 * (Loop - 1)) + SumLoop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, (5 * (Loop - 1)) + SumLoop, 10);
   value := Log_LV_Title[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF (5 * (Loop - 1)) + SumLoop >= ARRAY_MIN AND (5 * (Loop - 1)) + SumLoop <= ARRAY_MAX THEN
       value := Log_LV_Title[(5 * (Loop - 1)) + SumLoop];
   END_IF

예시:

❌ 위험: value := Log_LV_Title[(5 * (Loop - 1)) + SumLoop]; // 범위 검사 없음!

✅ 안전: IF (5 * (Loop - 1)) + SumLoop >= 1 AND (5 * (Loop - 1)) + SumLoop <= 10 THEN
value := Log_LV_Title[(5 * (Loop - 1)) + SumLoop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:1

설명: Log_LV_Data[(5 * (Loop - 1)) + SumLoop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF (5 * (Loop - 1)) + SumLoop >= 1 AND
      (5 * (Loop - 1)) + SumLoop <= 10 THEN
       value := Log_LV_Data[(5 * (Loop - 1)) + SumLoop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, (5 * (Loop - 1)) + SumLoop, 10);
   value := Log_LV_Data[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF (5 * (Loop - 1)) + SumLoop >= ARRAY_MIN AND (5 * (Loop - 1)) + SumLoop <= ARRAY_MAX THEN
       value := Log_LV_Data[(5 * (Loop - 1)) + SumLoop];
   END_IF

예시:

❌ 위험: value := Log_LV_Data[(5 * (Loop - 1)) + SumLoop]; // 범위 검사 없음!

✅ 안전: IF (5 * (Loop - 1)) + SumLoop >= 1 AND (5 * (Loop - 1)) + SumLoop <= 10 THEN
value := Log_LV_Data[(5 * (Loop - 1)) + SumLoop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:1

설명: LV_Msg_Sum[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := LV_Msg_Sum[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := LV_Msg_Sum[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := LV_Msg_Sum[Loop];
   END_IF

예시:

❌ 위험: value := LV_Msg_Sum[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := LV_Msg_Sum[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:1

설명: LV_Msg_Sum[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := LV_Msg_Sum[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := LV_Msg_Sum[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := LV_Msg_Sum[Loop];
   END_IF

예시:

❌ 위험: value := LV_Msg_Sum[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := LV_Msg_Sum[Loop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:1

설명: Log_LV_Data[(5 * (Loop - 1)) + SumLoop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF (5 * (Loop - 1)) + SumLoop >= 1 AND
      (5 * (Loop - 1)) + SumLoop <= 10 THEN
       value := Log_LV_Data[(5 * (Loop - 1)) + SumLoop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, (5 * (Loop - 1)) + SumLoop, 10);
   value := Log_LV_Data[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF (5 * (Loop - 1)) + SumLoop >= ARRAY_MIN AND (5 * (Loop - 1)) + SumLoop <= ARRAY_MAX THEN
       value := Log_LV_Data[(5 * (Loop - 1)) + SumLoop];
   END_IF

예시:

❌ 위험: value := Log_LV_Data[(5 * (Loop - 1)) + SumLoop]; // 범위 검사 없음!

✅ 안전: IF (5 * (Loop - 1)) + SumLoop >= 1 AND (5 * (Loop - 1)) + SumLoop <= 10 THEN
value := Log_LV_Data[(5 * (Loop - 1)) + SumLoop];
ELSE
errorFlag := TRUE;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: Blink_Yellow: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Blink_Yellow <> NULL THEN
       value := Blink_Yellow^;
       // 또는 Blink_Yellow.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Blink_Yellow');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Blink_Yellow) THEN
       value := Blink_Yellow.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Blink_Yellow := ADR(targetVariable);
   IF Blink_Yellow = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Blink_Yellow = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Blink_Yellow^; // NULL 체크 없음!
value := Blink_Yellow.member; // NULL 체크 없음!

✅ 안전: IF Blink_Yellow <> NULL THEN
value := Blink_Yellow^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Blink_Yellow) THEN
value := Blink_Yellow.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: Blink_Red: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Blink_Red <> NULL THEN
       value := Blink_Red^;
       // 또는 Blink_Red.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Blink_Red');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Blink_Red) THEN
       value := Blink_Red.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Blink_Red := ADR(targetVariable);
   IF Blink_Red = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Blink_Red = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Blink_Red^; // NULL 체크 없음!
value := Blink_Red.member; // NULL 체크 없음!

✅ 안전: IF Blink_Red <> NULL THEN
value := Blink_Red^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Blink_Red) THEN
value := Blink_Red.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: Blink_Alarm: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Blink_Alarm <> NULL THEN
       value := Blink_Alarm^;
       // 또는 Blink_Alarm.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Blink_Alarm');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Blink_Alarm) THEN
       value := Blink_Alarm.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Blink_Alarm := ADR(targetVariable);
   IF Blink_Alarm = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Blink_Alarm = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Blink_Alarm^; // NULL 체크 없음!
value := Blink_Alarm.member; // NULL 체크 없음!

✅ 안전: IF Blink_Alarm <> NULL THEN
value := Blink_Alarm^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Blink_Alarm) THEN
value := Blink_Alarm.member;
END_IF
🔴 Critical [QA004] NULL 체크 없이 포인터 사용

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: Blink_Idle: NULL 검사 없이 포인터/레퍼런스를 역참조하여 런타임 오류 가능

⚠️ 위험성:

NULL 포인터를 역참조하면 다음과 같은 심각한 문제가 발생합니다: 1. PLC 런타임 크래시 (심각한 경우) 2. 예측 불가능한 메모리 접근 3. 시스템 전체 중단 가능성 4. 안전 시스템 기능 상실 NULL 포인터는 유효한 메모리 주소를 가리키지 않으므로, 역참조 시도는 항상 오류를 발생시킵니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 NULL 체크 (가장 권장)
   IF Blink_Idle <> NULL THEN
       value := Blink_Idle^;
       // 또는 Blink_Idle.member
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       LogError('Null pointer detected: Blink_Idle');
   END_IF

2. __ISVALIDREF 내장 함수 사용 (REFERENCE 타입)
   IF __ISVALIDREF(Blink_Idle) THEN
       value := Blink_Idle.member;
   ELSE
       errorFlag := TRUE;
   END_IF

3. 초기화 시 NULL 검증
   Blink_Idle := ADR(targetVariable);
   IF Blink_Idle = NULL THEN
       LogError('Failed to get address');
       RETURN;
   END_IF

4. 방어적 프로그래밍
   // 함수 시작 시 검증
   IF Blink_Idle = NULL THEN
       RETURN;
   END_IF

예시:

❌ 위험: value := Blink_Idle^; // NULL 체크 없음!
value := Blink_Idle.member; // NULL 체크 없음!

✅ 안전: IF Blink_Idle <> NULL THEN
value := Blink_Idle^;
ELSE
errorFlag := TRUE;
END_IF

// REFERENCE 타입의 경우
IF __ISVALIDREF(Blink_Idle) THEN
value := Blink_Idle.member;
END_IF
🔴 Critical [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: SYS_Signal: 321줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SYS_Signal = 321줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: DX_INF_State_Process = eProcess_Processing: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Process >= (eProcess_Processing - 1.0E-6) AND
      DX_INF_State_Process <= (eProcess_Processing + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Process >= eProcess_Processing THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Process * 10.0);
   intTarget := REAL_TO_DINT(eProcess_Processing * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Process = eProcess_Processing THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: DX_Red_Signal = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_Red_Signal - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_Red_Signal >= (FALSE - 1.0E-6) AND
      DX_Red_Signal <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_Red_Signal >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_Red_Signal * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_Red_Signal = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_Red_Signal - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: DX_Green_Signal = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_Green_Signal - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_Green_Signal >= (FALSE - 1.0E-6) AND
      DX_Green_Signal <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_Green_Signal >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_Green_Signal * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_Green_Signal = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_Green_Signal - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: mDO16_02_REAR_SIGNAL_TOWER_YELLOW = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(mDO16_02_REAR_SIGNAL_TOWER_YELLOW - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF mDO16_02_REAR_SIGNAL_TOWER_YELLOW >= (FALSE - 1.0E-6) AND
      mDO16_02_REAR_SIGNAL_TOWER_YELLOW <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF mDO16_02_REAR_SIGNAL_TOWER_YELLOW >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(mDO16_02_REAR_SIGNAL_TOWER_YELLOW * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF mDO16_02_REAR_SIGNAL_TOWER_YELLOW = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(mDO16_02_REAR_SIGNAL_TOWER_YELLOW - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: mDO16_00_REAR_SIGNAL_TOWER_RED = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(mDO16_00_REAR_SIGNAL_TOWER_RED - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF mDO16_00_REAR_SIGNAL_TOWER_RED >= (FALSE - 1.0E-6) AND
      mDO16_00_REAR_SIGNAL_TOWER_RED <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF mDO16_00_REAR_SIGNAL_TOWER_RED >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(mDO16_00_REAR_SIGNAL_TOWER_RED * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF mDO16_00_REAR_SIGNAL_TOWER_RED = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(mDO16_00_REAR_SIGNAL_TOWER_RED - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: DX_Yellow_Signal = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_Yellow_Signal - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_Yellow_Signal >= (FALSE - 1.0E-6) AND
      DX_Yellow_Signal <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_Yellow_Signal >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_Yellow_Signal * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_Yellow_Signal = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_Yellow_Signal - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: DX_Red_Signal = FALSE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_Red_Signal - FALSE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_Red_Signal >= (FALSE - 1.0E-6) AND
      DX_Red_Signal <= (FALSE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_Red_Signal >= FALSE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_Red_Signal * 10.0);
   intTarget := REAL_TO_DINT(FALSE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_Red_Signal = FALSE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_Red_Signal - FALSE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: DX_INF_State_Process = eProcess_Idle: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Process - eProcess_Idle) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Process >= (eProcess_Idle - 1.0E-6) AND
      DX_INF_State_Process <= (eProcess_Idle + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Process >= eProcess_Idle THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Process * 10.0);
   intTarget := REAL_TO_DINT(eProcess_Idle * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Process = eProcess_Idle THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Process - eProcess_Idle) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: DX_INF_State_Process = eProcess_Ready: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Process - eProcess_Ready) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Process >= (eProcess_Ready - 1.0E-6) AND
      DX_INF_State_Process <= (eProcess_Ready + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Process >= eProcess_Ready THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Process * 10.0);
   intTarget := REAL_TO_DINT(eProcess_Ready * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Process = eProcess_Ready THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Process - eProcess_Ready) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: DX_CTC_PM_Mode = 1: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_CTC_PM_Mode - 1) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_CTC_PM_Mode >= (1 - 1.0E-6) AND
      DX_CTC_PM_Mode <= (1 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_CTC_PM_Mode >= 1 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_CTC_PM_Mode * 10.0);
   intTarget := REAL_TO_DINT(1 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_CTC_PM_Mode = 1 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_CTC_PM_Mode - 1) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: DX_CFG_Run_Mode = 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_CFG_Run_Mode - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_CFG_Run_Mode >= (0 - 1.0E-6) AND
      DX_CFG_Run_Mode <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_CFG_Run_Mode >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_CFG_Run_Mode * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_CFG_Run_Mode = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_CFG_Run_Mode - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: DX_CFG_Signal_Idle_Action = 0: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_CFG_Signal_Idle_Action - 0) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_CFG_Signal_Idle_Action >= (0 - 1.0E-6) AND
      DX_CFG_Signal_Idle_Action <= (0 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_CFG_Signal_Idle_Action >= 0 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_CFG_Signal_Idle_Action * 10.0);
   intTarget := REAL_TO_DINT(0 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_CFG_Signal_Idle_Action = 0 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_CFG_Signal_Idle_Action - 0) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: DX_CFG_Signal_Idle_Action = 1: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_CFG_Signal_Idle_Action - 1) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_CFG_Signal_Idle_Action >= (1 - 1.0E-6) AND
      DX_CFG_Signal_Idle_Action <= (1 + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_CFG_Signal_Idle_Action >= 1 THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_CFG_Signal_Idle_Action * 10.0);
   intTarget := REAL_TO_DINT(1 * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_CFG_Signal_Idle_Action = 1 THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_CFG_Signal_Idle_Action - 1) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: Q = TRUE: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(Q - TRUE) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF Q >= (TRUE - 1.0E-6) AND
      Q <= (TRUE + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF Q >= TRUE THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(Q * 10.0);
   intTarget := REAL_TO_DINT(TRUE * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF Q = TRUE THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(Q - TRUE) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA005] 부동소수점 직접 비교 사용

카테고리: 부동소수점 연산

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: DX_INF_State_Process = eProcess_Processing: REAL/LREAL 타입을 직접 비교하여 오작동 가능

⚠️ 위험성:

부동소수점 연산의 특성상 정확히 같은 값을 가지기 어렵습니다: 1. 반올림 오차 누적 (0.1 + 0.2 ≠ 0.3) 2. 서로 다른 연산 순서에 따른 미세한 차이 3. 컴파일러 최적화에 따른 정밀도 변화 4. 하드웨어 부동소수점 유닛(FPU)의 구현 차이 예시: result := 0.1 + 0.2; IF result = 0.3 THEN // FALSE가 될 수 있음! // 이 코드는 실행되지 않을 수 있음 END_IF 실제 값: 0.30000000000000004 (부동소수점 표현의 한계)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Epsilon 비교 사용 (가장 권장)
   VAR CONSTANT
       EPSILON : LREAL := 1.0E-6; // 허용 오차
   END_VAR

   IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
       // 값이 "거의 같음"
   END_IF

2. 범위 비교 사용
   IF DX_INF_State_Process >= (eProcess_Processing - 1.0E-6) AND
      DX_INF_State_Process <= (eProcess_Processing + 1.0E-6) THEN
       // 허용 범위 내에 있음
   END_IF

3. 부등호 비교로 변경 (가능한 경우)
   // = 대신 >= 또는 <= 사용
   IF DX_INF_State_Process >= eProcess_Processing THEN
       // ...
   END_IF

4. 정수 연산으로 변환 (가능한 경우)
   // 0.1 단위 비교 → 1 단위 비교
   intValue := REAL_TO_DINT(DX_INF_State_Process * 10.0);
   intTarget := REAL_TO_DINT(eProcess_Processing * 10.0);
   IF intValue = intTarget THEN
       // 정확한 비교 가능
   END_IF

예시:

❌ 위험: IF DX_INF_State_Process = eProcess_Processing THEN
// 부동소수점 직접 비교!
END_IF

✅ 안전: CONST EPSILON : LREAL := 1.0E-6; END_CONST
IF ABS(DX_INF_State_Process - eProcess_Processing) < EPSILON THEN
// 안전한 비교
END_IF

// 실제 사례
temperature : REAL := 25.5;
setpoint : REAL := 25.5;

// 잘못된 방법
IF temperature = setpoint THEN // 위험!

// 올바른 방법
IF ABS(temperature - setpoint) < 0.1 THEN // 안전!
🔴 Critical [QA003] 배열 범위 검사 없이 접근

카테고리: 메모리 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: pALM[Loop]: 인덱스 범위 검사 없이 배열에 접근하여 메모리 오류 가능

⚠️ 위험성:

배열 범위를 벗어난 인덱스로 접근하면 다음과 같은 위험이 발생합니다: 1. 잘못된 메모리 영역 읽기/쓰기 2. 다른 변수의 값이 의도치 않게 변경됨 3. PLC 런타임 오류 또는 예측 불가능한 동작 4. 시스템 크래시 가능성 예: ARRAY[1..10] 에 index=15 로 접근하면 메모리 침범 발생
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 명시적 범위 검사 추가 (가장 권장)
   IF Loop >= 1 AND
      Loop <= 10 THEN
       value := pALM[Loop];
   ELSE
       // 에러 처리
       errorFlag := TRUE;
       value := 0; // 기본값
   END_IF

2. LIMIT 함수 사용
   safeIndex := LIMIT(1, Loop, 10);
   value := pALM[safeIndex];

3. 배열 크기 상수 정의 후 검증
   VAR CONSTANT
       ARRAY_MIN : INT := 1;
       ARRAY_MAX : INT := 10;
   END_VAR

   IF Loop >= ARRAY_MIN AND Loop <= ARRAY_MAX THEN
       value := pALM[Loop];
   END_IF

예시:

❌ 위험: value := pALM[Loop]; // 범위 검사 없음!

✅ 안전: IF Loop >= 1 AND Loop <= 10 THEN
value := pALM[Loop];
ELSE
errorFlag := TRUE;
END_IF
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\MAIN.TcPOU:2

설명: Boot: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBoot

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\MAIN.TcPOU:3

설명: Simulation: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isSimulation

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\MAIN.TcPOU:4

설명: IOCheck: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isIOCheck

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\MAIN.TcPOU:11

설명: bGet_NetID: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBGet_NetID

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\MAIN_10ms.TcPOU:2

설명: Boot: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBoot

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Add_EventLog_buffer.TcPOU:2

설명: sObject: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSObject

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Add_EventLog_buffer.TcPOU:3

설명: sData: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSData

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_CheckMainZone.TcPOU:3

설명: Heater_Control_Mode: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iHeater_Control_Mode

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:3

설명: Start: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iStart

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:4

설명: End: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iEnd

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:6

설명: ApcSuccessJump_Step: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iApcSuccessJump_Step

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:7

설명: Jump_Step: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iJump_Step

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:8

설명: Jump_Cycle: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iJump_Cycle

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:18

설명: NextStep: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oNextStep

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:3

설명: Start: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iStart

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:4

설명: End: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iEnd

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:6

설명: ApcSuccessJump_Step: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iApcSuccessJump_Step

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:7

설명: Jump_Step: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iJump_Step

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:8

설명: Jump_Cycle: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iJump_Cycle

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:18

설명: NextStep: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oNextStep

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Extract_Array.TcPOU:2

설명: Message: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iMessage

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA006] 사용되지 않을 가능성이 있는 변수

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Extract_Array.TcPOU:11

설명: Temp: 변수 이름이 임시/테스트 목적으로 보임

⚠️ 위험성:

사용되지 않는 변수는 다음 문제를 야기합니다: - 메모리 낭비 (PLC 메모리는 제한적) - 코드 가독성 저하 - 유지보수 혼란 (실제 사용 여부 불분명) - 디버깅 시 불필요한 변수 추적
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 변수가 실제로 사용되는지 확인
   - 로직 블록에서 Temp 사용 확인
   - 사용되지 않으면 삭제

2. 임시 변수는 명확한 이름 사용
   ❌ temp, tmp, test, dummy
   ✅ calculatedSpeed, tempPressure, testCounter

3. 주석으로 사용 목적 명시
   // 향후 센서 연결 예정
   Temp : STRING;

예시:

❌ 나쁜 예:
temp : INT; // 어디에 사용?
test : BOOL; // 테스트용인가, 운영용인가?

✅ 좋은 예:
calculatedSpeed : INT; // 계산된 속도
isMotorRunning : BOOL; // 모터 동작 상태
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Get_Parameter.TcPOU:2

설명: destAddr: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iDestAddr

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Get_Parameter.TcPOU:3

설명: findName: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iFindName

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Get_Parameter.TcPOU:4

설명: srcAddr: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSrcAddr

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Get_Parameter.TcPOU:5

설명: srcSize: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSrcSize

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Func.TcPOU:3

설명: sDiviceID: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSDiviceID

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Func.TcPOU:4

설명: sEventID: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSEventID

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Func.TcPOU:5

설명: sStatus: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSStatus

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Process.TcPOU:3

설명: sObject: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSObject

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Process.TcPOU:4

설명: sStepName: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSStepName

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Process.TcPOU:5

설명: uiCntStep: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iUiCntStep

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Process.TcPOU:6

설명: trendAddr: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iTrendAddr

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Process.TcPOU:18

설명: Index: 초기값 '14'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 14;  // Index의 의미
   END_VAR

   Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 14
   );
   END_TYPE

3. 주석으로 의미 설명
   Index : UINT := 14;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Parameter_Check.TcPOU:2

설명: findName: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iFindName

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Parameter_Check.TcPOU:3

설명: srcAddr: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSrcAddr

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Parameter_Check.TcPOU:4

설명: srcSize: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSrcSize

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_RealRound.TcPOU:2

설명: lValue: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iLValue

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_RealRound.TcPOU:3

설명: nDigit: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iNDigit

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Set_Parameter.TcPOU:2

설명: paramAddr: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iParamAddr

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Set_Parameter.TcPOU:3

설명: paramSize: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iParamSize

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Set_Parameter.TcPOU:4

설명: srcAddr: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSrcAddr

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_StepName_Search.TcPOU:2

설명: searchName: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSearchName

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Table_Check.TcPOU:2

설명: CheckNum: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iCheckNum

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Table_Check.TcPOU:3

설명: MaxTable: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iMaxTable

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Time_Conversion.TcPOU:3

설명: In_StrTime: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iIn_StrTime

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\Get_IEEE754.TcPOU:2

설명: sData: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSData

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\Put_IEEE754.TcPOU:2

설명: rData: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iRData

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\Put_IEEE754.TcPOU:5

설명: w: 한 글자 변수명은 피하세요 (의미 있는 이름 사용)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: w

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_ROUND.TcPOU:2

설명: lValue: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iLValue

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_ROUND.TcPOU:3

설명: nDigit: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iNDigit

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_ROUND.TcPOU:4

설명: bRound: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iBRound

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:13

설명: paramResult: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isParamResult

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:3

설명: fSetpointValue: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iFSetpointValue

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:4

설명: fActualValue: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iFActualValue

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:6

설명: bReset: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iBReset

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:8

설명: fCtrlCycleTime: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iFCtrlCycleTime

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:14

설명: fKp: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iFKp

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:15

설명: fTn: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iFTn

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:16

설명: fTv: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iFTv

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:17

설명: fTd: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iFTd

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:19

설명: bDirection: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iBDirection

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:22

설명: fCtrlOutput: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFCtrlOutput

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:23

설명: nErrorStatus: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oNErrorStatus

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:33

설명: fE: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // fE의 의미
   END_VAR

   fE := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   fE : LREAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:34

설명: fE_1: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // fE_1의 의미
   END_VAR

   fE_1 := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   fE_1 : LREAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:35

설명: fY: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // fY의 의미
   END_VAR

   fY := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   fY : LREAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:36

설명: fY_1: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // fY_1의 의미
   END_VAR

   fY_1 := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   fY_1 : LREAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:37

설명: fYP: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // fYP의 의미
   END_VAR

   fYP := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   fYP : LREAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:38

설명: fYI: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // fYI의 의미
   END_VAR

   fYI := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   fYI : LREAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:39

설명: fYI_1: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // fYI_1의 의미
   END_VAR

   fYI_1 := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   fYI_1 : LREAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:40

설명: fYD: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // fYD의 의미
   END_VAR

   fYD := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   fYD : LREAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:41

설명: fYD_1: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // fYD_1의 의미
   END_VAR

   fYD_1 := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   fYD_1 : LREAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:43

설명: bInit: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBInit

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:44

설명: bIsIPart: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBIsIPart

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:45

설명: bIsDPart: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBIsDPart

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:47

설명: fDi: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // fDi의 의미
   END_VAR

   fDi := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   fDi : LREAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:48

설명: fDd: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // fDd의 의미
   END_VAR

   fDd := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   fDd : LREAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:49

설명: fCd: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // fCd의 의미
   END_VAR

   fCd := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   fCd : LREAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:51

설명: fCtrlCycleTimeOld: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // fCtrlCycleTimeOld의 의미
   END_VAR

   fCtrlCycleTimeOld := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   fCtrlCycleTimeOld : LREAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:52

설명: fKpOld: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // fKpOld의 의미
   END_VAR

   fKpOld := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   fKpOld : LREAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:53

설명: fTnOld: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // fTnOld의 의미
   END_VAR

   fTnOld := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   fTnOld : LREAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:54

설명: fTvOld: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // fTvOld의 의미
   END_VAR

   fTvOld := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   fTvOld : LREAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:55

설명: fTdOld: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // fTdOld의 의미
   END_VAR

   fTdOld := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   fTdOld : LREAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:5

설명: iSet: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // iSet의 의미
   END_VAR

   iSet := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   iSet : REAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:6

설명: iActual: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // iActual의 의미
   END_VAR

   iActual := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   iActual : REAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:10

설명: oSet: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // oSet의 의미
   END_VAR

   oSet := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   oSet : REAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:11

설명: oMin: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // oMin의 의미
   END_VAR

   oMin := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   oMin : REAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:12

설명: oMax: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // oMax의 의미
   END_VAR

   oMax := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   oMax : REAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:13

설명: oAvg: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // oAvg의 의미
   END_VAR

   oAvg := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   oAvg : REAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:17

설명: Total: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // Total의 의미
   END_VAR

   Total := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   Total : REAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:24

설명: iVoltage: 초기값 '32767.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 32767.0;  // iVoltage의 의미
   END_VAR

   iVoltage := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 32767.0
   );
   END_TYPE

3. 주석으로 의미 설명
   iVoltage : REAL := 32767.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:25

설명: iRatio: 초기값 '1.33'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 1.33;  // iRatio의 의미
   END_VAR

   iRatio := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 1.33
   );
   END_TYPE

3. 주석으로 의미 설명
   iRatio : REAL := 1.33;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:27

설명: Parameter_Use: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iParameter_Use

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:28

설명: Parts_Use: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iParts_Use

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:68

설명: ControlSet: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // ControlSet의 의미
   END_VAR

   ControlSet := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   ControlSet : REAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:69

설명: ControlSet_Dev: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // ControlSet_Dev의 의미
   END_VAR

   ControlSet_Dev := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   ControlSet_Dev : REAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:72

설명: Deviation: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // Deviation의 의미
   END_VAR

   Deviation := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   Deviation : REAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:73

설명: Deviation_Ab: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // Deviation_Ab의 의미
   END_VAR

   Deviation_Ab := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   Deviation_Ab : REAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:74

설명: Deviation_Set: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // Deviation_Set의 의미
   END_VAR

   Deviation_Set := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   Deviation_Set : REAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:77

설명: Gas_Deviation: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // Gas_Deviation의 의미
   END_VAR

   Gas_Deviation := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   Gas_Deviation : REAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:23

설명: bTriger: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBTriger

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Explict_Message_Timer.TcPOU:2

설명: bEnable: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iBEnable

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Explict_Message_Timer.TcPOU:3

설명: timeInterval: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iTimeInterval

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Explict_Message_Timer.TcPOU:7

설명: bBlink: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oBBlink

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Heater_Group_Scan.TcPOU:2

설명: InValue: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iInValue

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Heater_Group_Scan.TcPOU:3

설명: DelayTime: 초기값 '5'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 5;  // DelayTime의 의미
   END_VAR

   DelayTime := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 5
   );
   END_TYPE

3. 주석으로 의미 설명
   DelayTime : REAL := 5;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Heater_Group_Scan.TcPOU:3

설명: DelayTime: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iDelayTime

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:3

설명: Master_NetID: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iMaster_NetID

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:4

설명: UpdateTime: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iUpdateTime

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:8

설명: bError: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oBError

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:9

설명: nLostFrames: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oNLostFrames

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:10

설명: fFramesPerSecond: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFFramesPerSecond

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:11

설명: nLostQueuedFrames: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oNLostQueuedFrames

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:12

설명: fQueuedFramesPerSecond: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFQueuedFramesPerSecond

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:13

설명: DeviceState: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oDeviceState

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:14

설명: LinkState: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oLinkState

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:25

설명: trgValue: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isTrgValue

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal.TcPOU:13

설명: ioInterlock: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIoInterlock

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_BurnBox.TcPOU:11

설명: ioInterlock: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIoInterlock

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_TempDelay.TcPOU:2

설명: InValue: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iInValue

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_TempDelay.TcPOU:3

설명: DelayTime: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iDelayTime

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_TempDelay.TcPOU:15

설명: TimerExecute: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isTimerExecute

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:6

설명: iInitStartTime: 초기값 '6'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 6;  // iInitStartTime의 의미
   END_VAR

   iInitStartTime := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 6
   );
   END_TYPE

3. 주석으로 의미 설명
   iInitStartTime : REAL := 6;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:7

설명: iInitEndTime: 초기값 '6'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 6;  // iInitEndTime의 의미
   END_VAR

   iInitEndTime := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 6
   );
   END_TYPE

3. 주석으로 의미 설명
   iInitEndTime : REAL := 6;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:8

설명: iExecuteStartTime: 초기값 '6'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 6;  // iExecuteStartTime의 의미
   END_VAR

   iExecuteStartTime := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 6
   );
   END_TYPE

3. 주석으로 의미 설명
   iExecuteStartTime : REAL := 6;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:9

설명: iExecuteEndTime: 초기값 '6'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 6;  // iExecuteEndTime의 의미
   END_VAR

   iExecuteEndTime := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 6
   );
   END_TYPE

3. 주석으로 의미 설명
   iExecuteEndTime : REAL := 6;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:10

설명: iCalTimeout: 초기값 '2.5'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 2.5;  // iCalTimeout의 의미
   END_VAR

   iCalTimeout := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 2.5
   );
   END_TYPE

3. 주석으로 의미 설명
   iCalTimeout : REAL := 2.5;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:66

설명: bInit: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBInit

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:78

설명: rINIT_STATUS: 초기값 '255'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 255;  // rINIT_STATUS의 의미
   END_VAR

   rINIT_STATUS := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 255
   );
   END_TYPE

3. 주석으로 의미 설명
   rINIT_STATUS : USINT := 255;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:79

설명: rINIT_RESPONSE: 초기값 '255'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 255;  // rINIT_RESPONSE의 의미
   END_VAR

   rINIT_RESPONSE := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 255
   );
   END_TYPE

3. 주석으로 의미 설명
   rINIT_RESPONSE : BYTE := 255;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:116

설명: bMon: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBMon

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:143

설명: rCAL_RESPONSE: 초기값 '255'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 255;  // rCAL_RESPONSE의 의미
   END_VAR

   rCAL_RESPONSE := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 255
   );
   END_TYPE

3. 주석으로 의미 설명
   rCAL_RESPONSE : BYTE := 255;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:144

설명: rCAL_STATUS: 초기값 '255'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 255;  // rCAL_STATUS의 의미
   END_VAR

   rCAL_STATUS := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 255
   );
   END_TYPE

3. 주석으로 의미 설명
   rCAL_STATUS : USINT := 255;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:147

설명: ZeroShiftBackup: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // ZeroShiftBackup의 의미
   END_VAR

   ZeroShiftBackup := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   ZeroShiftBackup : REAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Signal_2BYTE.TcPOU:2

설명: ALARM_Data: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iALARM_Data

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Signal_2BYTE.TcPOU:10

설명: iValue: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isIValue

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:8

설명: WS_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iWS_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:9

설명: Spike_PV_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSpike_PV_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:10

설명: Profile_PV_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iProfile_PV_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:12

설명: Temp_DEV_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iTemp_DEV_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:14

설명: Short_DEV_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iShort_DEV_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:15

설명: Short_WS_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iShort_WS_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:17

설명: TempMode: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iTempMode

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:7

설명: Spike_PV_Value_1: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSpike_PV_Value_1

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:8

설명: Spike_PV_Value_2: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSpike_PV_Value_2

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:10

설명: Profile_PV_Value_1: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iProfile_PV_Value_1

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:11

설명: Profile_PV_Value_2: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iProfile_PV_Value_2

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:13

설명: Temp_DEV_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iTemp_DEV_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:15

설명: TempMode: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iTempMode

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:6

설명: Spike_PV_Value_1: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSpike_PV_Value_1

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:7

설명: Spike_PV_Value_2: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSpike_PV_Value_2

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:9

설명: Profile_PV_Value_1: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iProfile_PV_Value_1

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:10

설명: Profile_PV_Value_2: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iProfile_PV_Value_2

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:12

설명: Temp_DEV_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iTemp_DEV_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:14

설명: TempMode_1: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iTempMode_1

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:15

설명: TempMode_2: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iTempMode_2

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:16

설명: Old_TempMode_1: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iOld_TempMode_1

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:17

설명: Old_TempMode_2: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iOld_TempMode_2

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Timer.TcPOU:2

설명: IN: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iIN

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Timer.TcPOU:3

설명: PT: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iPT

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Timer.TcPOU:6

설명: Q: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oQ

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Timer.TcPOU:6

설명: Q: 한 글자 변수명은 피하세요 (의미 있는 이름 사용)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oQ

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Timer.TcPOU:13

설명: N100NS: 초기값 '10000'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 10000;  // N100NS의 의미
   END_VAR

   N100NS := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 10000
   );
   END_TYPE

3. 주석으로 의미 설명
   N100NS : UINT := 10000;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:21

설명: bInit: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBInit

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:7

설명: Condition: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iCondition

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:8

설명: WS_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iWS_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:9

설명: PV_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iPV_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:10

설명: Low_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iLow_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:11

설명: High_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iHigh_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig.TcPOU:7

설명: WS_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iWS_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig.TcPOU:8

설명: PV_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iPV_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig.TcPOU:9

설명: Low_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iLow_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig.TcPOU:10

설명: High_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iHigh_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig_Sign.TcPOU:7

설명: WS_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iWS_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig_Sign.TcPOU:8

설명: PV_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iPV_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig_Sign.TcPOU:9

설명: Low_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iLow_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig_Sign.TcPOU:10

설명: High_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iHigh_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:36

설명: bInit: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBInit

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:37

설명: bController_Alarm: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBController_Alarm

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:38

설명: bBuff_Controller_Alarm: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBBuff_Controller_Alarm

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:64

설명: Parameter_Start_Step: 초기값 '220'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 220;  // Parameter_Start_Step의 의미
   END_VAR

   Parameter_Start_Step := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 220
   );
   END_TYPE

3. 주석으로 의미 설명
   Parameter_Start_Step : BYTE := 220;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:66

설명: OffSet_Start_Step: 초기값 '190'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 190;  // OffSet_Start_Step의 의미
   END_VAR

   OffSet_Start_Step := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 190
   );
   END_TYPE

3. 주석으로 의미 설명
   OffSet_Start_Step : BYTE := 190;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:94

설명: bTest_flag: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBTest_flag

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:33

설명: O2_Cal_Delay_Value: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iO2_Cal_Delay_Value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:10

설명: G_LIFE_Timeout: 초기값 '60'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 60;  // G_LIFE_Timeout의 의미
   END_VAR

   G_LIFE_Timeout := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 60
   );
   END_TYPE

3. 주석으로 의미 설명
   G_LIFE_Timeout : REAL := 60;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:19

설명: iInitCtrl: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isIInitCtrl

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:20

설명: iExeCtrl: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isIExeCtrl

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:21

설명: iCalCtrl: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isICalCtrl

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:11

설명: oBoatMode: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iOBoatMode

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:13

설명: oBoatMaintPosition: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iOBoatMaintPosition

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:15

설명: oBoat_PrameterTable_Num: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iOBoat_PrameterTable_Num

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:17

설명: oBoatTablePosition_1: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iOBoatTablePosition_1

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:18

설명: oBoatTablePosition_2: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iOBoatTablePosition_2

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:19

설명: oBoatTablePosition_3: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iOBoatTablePosition_3

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:20

설명: oBoatTablePosition_4: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iOBoatTablePosition_4

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:21

설명: oBoatTablePosition_5: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iOBoatTablePosition_5

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:23

설명: oBoatTableSpeed_1: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iOBoatTableSpeed_1

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:24

설명: oBoatTableSpeed_2: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iOBoatTableSpeed_2

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:25

설명: oBoatTableSpeed_3: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iOBoatTableSpeed_3

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:26

설명: oBoatTableSpeed_4: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iOBoatTableSpeed_4

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:27

설명: oBoatTableSpeed_5: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iOBoatTableSpeed_5

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:28

설명: oBoatUpSpeed: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iOBoatUpSpeed

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:31

설명: oRotate_Speed: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iORotate_Speed

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:35

설명: Connected: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oConnected

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:37

설명: iBoatCurrentPosition: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoatCurrentPosition

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:38

설명: iBoatInitPosition: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoatInitPosition

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:39

설명: iBoatHomePosition: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoatHomePosition

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:40

설명: iBoatUpPosition: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoatUpPosition

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:41

설명: iBoatDownPosition: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoatDownPosition

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:42

설명: iBoatMaintPosition01: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoatMaintPosition01

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:43

설명: iBoatMaintPosition02: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoatMaintPosition02

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:44

설명: iBoatMaintPosition03: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoatMaintPosition03

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:46

설명: iBoatCurrentSpeed: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoatCurrentSpeed

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:47

설명: iBoatAutoSpeed: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoatAutoSpeed

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:48

설명: iBoatJogSpeed: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoatJogSpeed

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:49

설명: iBoatInitSpeed: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoatInitSpeed

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:51

설명: iBoatACAC: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoatACAC

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:52

설명: iBoatACC: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoatACC

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:53

설명: iBoatDEC: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoatDEC

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:54

설명: iBoat_ConversionRatio: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoat_ConversionRatio

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:56

설명: iBoat_Servo: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoat_Servo

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:57

설명: iBoat_Break: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoat_Break

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:58

설명: iBoat_TP_Mode: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoat_TP_Mode

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:59

설명: iBoat_HeaterShutter_Request_Mode: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoat_HeaterShutter_Request_Mode

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:61

설명: iBoatStatus: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoatStatus

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:62

설명: iBoatAlarmNum: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoatAlarmNum

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:65

설명: iBoat_Firmware: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIBoat_Firmware

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:68

설명: iRotate_States: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_States

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:69

설명: iRotate_AlarmNum: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_AlarmNum

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:71

설명: iRotate_Current_Position: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Current_Position

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:72

설명: iRotate_Current_Degree: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Current_Degree

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:74

설명: iRotate_Home_Position: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Home_Position

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:75

설명: iRotate_Init_Position: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Init_Position

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:76

설명: iRotate_Home_Speed: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Home_Speed

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:77

설명: iRotate_Init_Speed: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Init_Speed

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:78

설명: iRotate_Jog_Speed: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Jog_Speed

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:79

설명: iRotate_Current_Speed: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Current_Speed

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:81

설명: iRotate_ACAC: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_ACAC

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:82

설명: iRotate_AUTO_ACC: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_AUTO_ACC

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:83

설명: iRotate_AUTO_DEC: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_AUTO_DEC

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:84

설명: iRotate_TEMP: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_TEMP

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:86

설명: iRotate_Servo: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Servo

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:87

설명: iRotate_Break: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Break

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:88

설명: iRotate_TP_Mode: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_TP_Mode

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:90

설명: iRotate_Sum_Load: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Sum_Load

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:91

설명: iRotate_Cur_Load: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Cur_Load

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:93

설명: iRotate_Driver_Set_Speed: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Driver_Set_Speed

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:94

설명: iRotate_Driver_Current_Speed: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Driver_Current_Speed

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:95

설명: iRotate_Current_Load: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Current_Load

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:96

설명: iRotate_Torque: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Torque

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:97

설명: iRotate_Driver_Alarm: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Driver_Alarm

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:98

설명: iRotate_1round_Load: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_1round_Load

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:99

설명: iRotate_Moment_Load: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oIRotate_Moment_Load

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:114

설명: Connect_Check: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isConnect_Check

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:117

설명: Close_Bit: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isClose_Bit

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:144

설명: Monitor_Busy: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isMonitor_Busy

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:151

설명: PulseTommCheck: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isPulseTommCheck

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:157

설명: bInterlockTestFlag: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBInterlockTestFlag

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA006] 사용되지 않을 가능성이 있는 변수

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:5

설명: Temp: 변수 이름이 임시/테스트 목적으로 보임

⚠️ 위험성:

사용되지 않는 변수는 다음 문제를 야기합니다: - 메모리 낭비 (PLC 메모리는 제한적) - 코드 가독성 저하 - 유지보수 혼란 (실제 사용 여부 불분명) - 디버깅 시 불필요한 변수 추적
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 변수가 실제로 사용되는지 확인
   - 로직 블록에서 Temp 사용 확인
   - 사용되지 않으면 삭제

2. 임시 변수는 명확한 이름 사용
   ❌ temp, tmp, test, dummy
   ✅ calculatedSpeed, tempPressure, testCounter

3. 주석으로 사용 목적 명시
   // 향후 센서 연결 예정
   Temp : eMode_Function_TVLPV;

예시:

❌ 나쁜 예:
temp : INT; // 어디에 사용?
test : BOOL; // 테스트용인가, 운영용인가?

✅ 좋은 예:
calculatedSpeed : INT; // 계산된 속도
isMotorRunning : BOOL; // 모터 동작 상태
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:30

설명: VAC_O2Analyzer_Time: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iVAC_O2Analyzer_Time

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:18

설명: c: 한 글자 변수명은 피하세요 (의미 있는 이름 사용)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: c

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:23

설명: manualMode: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isManualMode

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:24

설명: paramResult: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isParamResult

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:8

설명: TempLimit_Min: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iTempLimit_Min

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:9

설명: TempLimit_Max: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iTempLimit_Max

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:40

설명: paramResult: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isParamResult

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:14

설명: manualMode: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isManualMode

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:15

설명: paramResult: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isParamResult

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:14

설명: m_ReadStart: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isM_ReadStart

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:15

설명: m_UpdateEndFlag: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isM_UpdateEndFlag

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:24

설명: bInit: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBInit

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:31

설명: _Triger_On: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: is_Triger_On

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:32

설명: _RunOn: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: is_RunOn

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:34

설명: bTest: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBTest

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:35

설명: bInformation: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBInformation

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:7

설명: RunRecipe: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iRunRecipe

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:8

설명: SubRecipeArray: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iSubRecipeArray

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:18

설명: Temp_Spec_In: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isTemp_Spec_In

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:31

설명: t: 한 글자 변수명은 피하세요 (의미 있는 이름 사용)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: t

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:86

설명: paramResult: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isParamResult

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:104

설명: End_Condition: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isEnd_Condition

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:105

설명: Hold_Step_State: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isHold_Step_State

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:107

설명: DCOP_SPOT_FLAG: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isDCOP_SPOT_FLAG

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:109

설명: Mon_Check_State: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isMon_Check_State

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:110

설명: Sub_Mon_Check_State: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isSub_Mon_Check_State

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:189

설명: Sub_Temp_Spec_In: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isSub_Temp_Spec_In

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:212

설명: Sub_End_Condition: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isSub_End_Condition

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:245

설명: Pause_State: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isPause_State

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:251

설명: Sub_LineHeater_Check: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isSub_LineHeater_Check

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:253

설명: Total_Thickness: 초기값 '0.000'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.000;  // Total_Thickness의 의미
   END_VAR

   Total_Thickness := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.000
   );
   END_TYPE

3. 주석으로 의미 설명
   Total_Thickness : REAL := 0.000;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:254

설명: Sub_Total_Thickness: 초기값 '0.000'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.000;  // Sub_Total_Thickness의 의미
   END_VAR

   Sub_Total_Thickness := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.000
   );
   END_TYPE

3. 주석으로 의미 설명
   Sub_Total_Thickness : REAL := 0.000;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:346

설명: DColl_Use: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isDColl_Use

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:391

설명: Boat_Down_Step_Check: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBoat_Down_Step_Check

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:393

설명: Boat_Down_Remain_Time_Check: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBoat_Down_Remain_Time_Check

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:399

설명: CalibrationAllCheck: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isCalibrationAllCheck

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:18

설명: paramResult: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isParamResult

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:23

설명: Check_Wafer: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isCheck_Wafer

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:29

설명: Wafer_Charge_Check: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isWafer_Charge_Check

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:34

설명: tHeater_Off_IO: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isTHeater_Off_IO

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:35

설명: tHeater_On_IO: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isTHeater_On_IO

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:42

설명: STS_Check: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isSTS_Check

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:45

설명: tSub_Heater_On_IO: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isTSub_Heater_On_IO

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:51

설명: tCap_Heater_On_IO: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isTCap_Heater_On_IO

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:57

설명: tLine_Heater_On_IO: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isTLine_Heater_On_IO

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:62

설명: bX20_Error: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBX20_Error

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:63

설명: bHeater_Off_ELB: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBHeater_Off_ELB

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:64

설명: bHeater_Off_SCR: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBHeater_Off_SCR

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:65

설명: bHeater_Off_Temp: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBHeater_Off_Temp

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:66

설명: bHeater_Off_Door: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBHeater_Off_Door

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:67

설명: bHeater_Off_Leak: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBHeater_Off_Leak

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:75

설명: bError: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBError

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:36

설명: REAR_DOOR_Check: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isREAR_DOOR_Check

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:41

설명: REAR_FFU_Interlock_Check: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isREAR_FFU_Interlock_Check

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:45

설명: Exhaust_Valve_Interlock_Check: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isExhaust_Valve_Interlock_Check

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:225

설명: Buff_PUMP_RUN: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBuff_PUMP_RUN

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:226

설명: Buff_Scrubber: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBuff_Scrubber

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:228

설명: GAS_H2_FLOW: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isGAS_H2_FLOW

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:232

설명: GAS_S4_FLOW: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isGAS_S4_FLOW

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:236

설명: GAS_S6_FLOW: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isGAS_S6_FLOW

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:240

설명: GAS_P1_FLOW: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isGAS_P1_FLOW

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:244

설명: GAS_P2_FLOW: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isGAS_P2_FLOW

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:248

설명: GAS_F2_FLOW: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isGAS_F2_FLOW

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:252

설명: GAS_DIPAS_FLOW: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isGAS_DIPAS_FLOW

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:268

설명: P_Gas_Flow_Chk: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isP_Gas_Flow_Chk

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:269

설명: P_Gas_Reset: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isP_Gas_Reset

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:272

설명: bBypass: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBBypass

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:273

설명: bHeaterPower: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBHeaterPower

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:292

설명: H2_O2_Ratio_STS: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isH2_O2_Ratio_STS

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:312

설명: AV68_Open_Flag: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isAV68_Open_Flag

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:313

설명: HFV05_Open_Flag: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isHFV05_Open_Flag

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:17

설명: Result_Common_ITK: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isResult_Common_ITK

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:22

설명: i: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isI

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:60

설명: ZeroShiftBackup: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // ZeroShiftBackup의 의미
   END_VAR

   ZeroShiftBackup := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   ZeroShiftBackup : REAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:63

설명: Max_VG_Cal_Timeout: 초기값 '0.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.0;  // Max_VG_Cal_Timeout의 의미
   END_VAR

   Max_VG_Cal_Timeout := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.0
   );
   END_TYPE

3. 주석으로 의미 설명
   Max_VG_Cal_Timeout : REAL := 0.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:22

설명: Initial_Com: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isInitial_Com

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:24

설명: Boat_Load_Trig: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBoat_Load_Trig

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:25

설명: Wafer_Init_Trig: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isWafer_Init_Trig

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:27

설명: Boat_Interlock_Check: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBoat_Interlock_Check

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:28

설명: Boat_Interlock_Up_Check: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBoat_Interlock_Up_Check

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:29

설명: Boat_Interlock_Gas_Check: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBoat_Interlock_Gas_Check

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:14

설명: Sampling_Start: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isSampling_Start

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:18

설명: Open_Status: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isOpen_Status

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:19

설명: Close_Status: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isClose_Status

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:14

설명: bDeviation_Value_Low: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBDeviation_Value_Low

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:15

설명: bDeviation_Value_High: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBDeviation_Value_High

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:8

설명: Config_RSD_Action: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iConfig_RSD_Action

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:9

설명: Config_RSD_Position: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iConfig_RSD_Position

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:10

설명: Config_RSD_Pressure: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iConfig_RSD_Pressure

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:15

설명: Result_Common_ITK: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isResult_Common_ITK

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:3

설명: Boat_Data_Dev: 초기값 '3'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 3;  // Boat_Data_Dev의 의미
   END_VAR

   Boat_Data_Dev := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 3
   );
   END_TYPE

3. 주석으로 의미 설명
   Boat_Data_Dev : REAL := 3;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:2

설명: Boot: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBoot

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:12

설명: bCreate: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBCreate

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:13

설명: bTitle: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBTitle

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:2

설명: eInHeaterCtrlMode: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iEInHeaterCtrlMode

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:3

설명: fInSetTemp: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iFInSetTemp

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:4

설명: fInSpikeTC_PV: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iFInSpikeTC_PV

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:5

설명: fInProfileTC_PV: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iFInProfileTC_PV

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:6

설명: fInPowValue: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iFInPowValue

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:7

설명: stExternalParaSet: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iStExternalParaSet

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:8

설명: stExternalPIDSet: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iStExternalPIDSet

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:9

설명: stTVPIDSet: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iStTVPIDSet

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:12

설명: fOutRampValue: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFOutRampValue

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:13

설명: fOutRampCtrl: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFOutRampCtrl

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:14

설명: fOutPower: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFOutPower

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:15

설명: fMaxOvershoot: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFMaxOvershoot

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:16

설명: eCtrlState: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oECtrlState

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:17

설명: eAlarmStatus: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oEAlarmStatus

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:18

설명: bError: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oBError

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:19

설명: eErrorID: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oEErrorID

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:20

설명: eCtrlMode: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oECtrlMode

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:21

설명: fP_Out: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFP_Out

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:22

설명: fI_Out: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFI_Out

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:23

설명: fD_Out: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFD_Out

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:24

설명: fPID_Out: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFPID_Out

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:25

설명: bCAS_Tune: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oBCAS_Tune

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:26

설명: fCAS_Tune_Result: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFCAS_Tune_Result

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:27

설명: bACC_Tune: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oBACC_Tune

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:28

설명: fACC_RDNP_Result: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFACC_RDNP_Result

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:29

설명: fACC_SP_Lag_Result: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFACC_SP_Lag_Result

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:30

설명: fTV_Out_P: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFTV_Out_P

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:31

설명: fTV_Out_I: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFTV_Out_I

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:32

설명: fTV_Out_D: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFTV_Out_D

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:33

설명: fTV_Out_PID_Sum: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFTV_Out_PID_Sum

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:34

설명: fTV_Out_Set: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFTV_Out_Set

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:2

설명: fInitTemp: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iFInitTemp

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:3

설명: fOut: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iFOut

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:4

설명: fKp: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iFKp

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:5

설명: tTask: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iTTask

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:6

설명: tCtrl: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iTCtrl

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:7

설명: tTimeConstant: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iTTimeConstant

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:10

설명: fValue: 출력 변수는 'o' 또는 'out' 접두사 사용 권장 (예: oSpeed)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: oFValue

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:16

설명: bInit: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBInit

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:20

설명: bParameterSet: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBParameterSet

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:21

설명: bModBusError: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBModBusError

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:22

설명: bSpike_TC_Sensor_Break: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBSpike_TC_Sensor_Break

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:23

설명: bProfile_TC_Sensor_Break: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBProfile_TC_Sensor_Break

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:24

설명: bOverTemp_TC_Sensor_Break: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBOverTemp_TC_Sensor_Break

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:29

설명: bWriteRegs: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBWriteRegs

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:30

설명: bErrorRegs: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBErrorRegs

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:2

설명: bParameterSet: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBParameterSet

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:6

설명: bParameterSet: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBParameterSet

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:7

설명: bModBusError: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBModBusError

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:8

설명: bWriteRegs: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBWriteRegs

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:63

설명: TC_OverRun: 초기값 '200'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 200;  // TC_OverRun의 의미
   END_VAR

   TC_OverRun := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 200
   );
   END_TYPE

3. 주석으로 의미 설명
   TC_OverRun : WORD := 200;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:64

설명: TC_UnderRun: 초기값 '300'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 300;  // TC_UnderRun의 의미
   END_VAR

   TC_UnderRun := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 300
   );
   END_TYPE

3. 주석으로 의미 설명
   TC_UnderRun : WORD := 300;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:66

설명: TC_Input_Address: 초기값 '8192'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 8192;  // TC_Input_Address의 의미
   END_VAR

   TC_Input_Address := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 8192
   );
   END_TYPE

3. 주석으로 의미 설명
   TC_Input_Address : WORD := 8192;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:67

설명: CJC_Input_Address: 초기값 '8448'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 8448;  // CJC_Input_Address의 의미
   END_VAR

   CJC_Input_Address := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 8448
   );
   END_TYPE

3. 주석으로 의미 설명
   CJC_Input_Address : WORD := 8448;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:68

설명: Version_Info_Address: 초기값 '8704'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 8704;  // Version_Info_Address의 의미
   END_VAR

   Version_Info_Address := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 8704
   );
   END_TYPE

3. 주석으로 의미 설명
   Version_Info_Address : WORD := 8704;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:73

설명: X20_UnitId: 초기값 '255'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 255;  // X20_UnitId의 의미
   END_VAR

   X20_UnitId := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 255
   );
   END_TYPE

3. 주석으로 의미 설명
   X20_UnitId : BYTE := 255;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:3

설명: bParamResult: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBParamResult

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:4

설명: bParameterSet: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBParameterSet

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:145

설명: bFirstCheck: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBFirstCheck

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:146

설명: bCompleteCheck: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBCompleteCheck

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:147

설명: bMV_Scheduling: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBMV_Scheduling

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:148

설명: bMV_Ramp: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBMV_Ramp

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:156

설명: bFirstCheckMV: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBFirstCheckMV

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:157

설명: bFirstCheckSV: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBFirstCheckSV

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:172

설명: ACC_One_Time_Check: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isACC_One_Time_Check

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Temp_Control.TcPOU:174

설명: AutoTune_End_DelayTime_Trig: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isAutoTune_End_DelayTime_Trig

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Function\F_TrendData_RealToString.TcPOU:3

설명: stringAddr: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iStringAddr

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Function\F_TrendData_RealToString.TcPOU:4

설명: realAddr: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iRealAddr

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:2

설명: Boot: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBoot

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:3

설명: Busy: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBusy

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:4

설명: Error: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isError

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:2

설명: Busy: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBusy

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:3

설명: Error: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isError

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:23

설명: WriteFlag: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isWriteFlag

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:2

설명: Boot: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBoot

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:5

설명: Busy: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBusy

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:6

설명: Error: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isError

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:14

설명: BE: 초기값 '3'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 3;  // BE의 의미
   END_VAR

   BE := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 3
   );
   END_TYPE

3. 주석으로 의미 설명
   BE : UINT := 3;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:15

설명: BR: 초기값 '4'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 4;  // BR의 의미
   END_VAR

   BR := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 4
   );
   END_TYPE

3. 주석으로 의미 설명
   BR : UINT := 4;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:2

설명: Busy: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBusy

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:3

설명: Error: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isError

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:2

설명: Error: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isError

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:2

설명: Busy: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isBusy

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:3

설명: Error: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isError

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:73

설명: LV_Log_Start_Trig: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isLV_Log_Start_Trig

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:74

설명: LV_Log_Title_Trig: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isLV_Log_Title_Trig

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:78

설명: Loging_All_Data: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isLoging_All_Data

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:15

설명: Alarm_States: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isAlarm_States

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:16

설명: Run_States: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isRun_States

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:17

설명: Idle_States: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isIdle_States

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:18

설명: PM_States: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isPM_States

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:19

설명: LP_States: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isLP_States

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:20

설명: LP2_States: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isLP2_States

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:22

설명: OldAlarm_States: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isOldAlarm_States

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:23

설명: OldRun_States: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isOldRun_States

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:24

설명: OldIdle_States: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isOldIdle_States

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:25

설명: OldPM_States: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isOldPM_States

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:26

설명: OldLP_States: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isOldLP_States

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivByte.TcPOU:2

설명: divisor: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iDivisor

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivDint.TcPOU:2

설명: divisor: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iDivisor

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivDWord.TcPOU:2

설명: divisor: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iDivisor

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivInt.TcPOU:2

설명: divisor: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iDivisor

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivLreal.TcPOU:2

설명: divisor: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iDivisor

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivReal.TcPOU:2

설명: divisor: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iDivisor

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivSInt.TcPOU:2

설명: divisor: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iDivisor

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivWord.TcPOU:2

설명: divisor: 입력 변수는 'i' 또는 'in' 접두사 사용 권장 (예: iTemperature)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: iDivisor

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Globale_VarCheck.TcGVL:15

설명: Check_Bit: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isCheck_Bit

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables.TcGVL:11

설명: pCollection: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPCollection

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables.TcGVL:18

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables.TcGVL: 전역 변수 10개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 10개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🟡 Warning [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables.TcGVL:20

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables.TcGVL: 전역 변수 11개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 11개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🟡 Warning [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables.TcGVL:21

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables.TcGVL: 전역 변수 12개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 12개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🟡 Warning [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables.TcGVL:22

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables.TcGVL: 전역 변수 13개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 13개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🟡 Warning [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables.TcGVL:24

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables.TcGVL: 전역 변수 14개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 14개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:8

설명: cTCPIP_Boat_Port: 초기값 '7000'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 7000;  // cTCPIP_Boat_Port의 의미
   END_VAR

   cTCPIP_Boat_Port := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 7000
   );
   END_TYPE

3. 주석으로 의미 설명
   cTCPIP_Boat_Port : UDINT := 7000;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:10

설명: cTCPIP_Rotate_Port: 초기값 '7000'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 7000;  // cTCPIP_Rotate_Port의 의미
   END_VAR

   cTCPIP_Rotate_Port := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 7000
   );
   END_TYPE

3. 주석으로 의미 설명
   cTCPIP_Rotate_Port : UDINT := 7000;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:13

설명: cTCPIP_LV_Port: 초기값 '200'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 200;  // cTCPIP_LV_Port의 의미
   END_VAR

   cTCPIP_LV_Port := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 200
   );
   END_TYPE

3. 주석으로 의미 설명
   cTCPIP_LV_Port : UDINT := 200;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:28

설명: cPM_Alarm_Index: 초기값 '200000'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 200000;  // cPM_Alarm_Index의 의미
   END_VAR

   cPM_Alarm_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 200000
   );
   END_TYPE

3. 주석으로 의미 설명
   cPM_Alarm_Index : UDINT := 200000;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:29

설명: cAlarmAllClear: 초기값 '65535'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 65535;  // cAlarmAllClear의 의미
   END_VAR

   cAlarmAllClear := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 65535
   );
   END_TYPE

3. 주석으로 의미 설명
   cAlarmAllClear : UDINT := 65535;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:32

설명: cDI_Address: 초기값 '101'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 101;  // cDI_Address의 의미
   END_VAR

   cDI_Address := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 101
   );
   END_TYPE

3. 주석으로 의미 설명
   cDI_Address : UINT := 101;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:33

설명: cDO_Address: 초기값 '301'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 301;  // cDO_Address의 의미
   END_VAR

   cDO_Address := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 301
   );
   END_TYPE

3. 주석으로 의미 설명
   cDO_Address : UINT := 301;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:34

설명: cDX_Address: 초기값 '401'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 401;  // cDX_Address의 의미
   END_VAR

   cDX_Address := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 401
   );
   END_TYPE

3. 주석으로 의미 설명
   cDX_Address : UINT := 401;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:35

설명: cDX_Persistent_Address: 초기값 '801'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 801;  // cDX_Persistent_Address의 의미
   END_VAR

   cDX_Persistent_Address := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 801
   );
   END_TYPE

3. 주석으로 의미 설명
   cDX_Persistent_Address : UINT := 801;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:36

설명: cDX_Driver_Address: 초기값 '901'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 901;  // cDX_Driver_Address의 의미
   END_VAR

   cDX_Driver_Address := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 901
   );
   END_TYPE

3. 주석으로 의미 설명
   cDX_Driver_Address : UINT := 901;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:37

설명: cAI_Address: 초기값 '1001'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 1001;  // cAI_Address의 의미
   END_VAR

   cAI_Address := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 1001
   );
   END_TYPE

3. 주석으로 의미 설명
   cAI_Address : UINT := 1001;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:38

설명: cAO_Address: 초기값 '5001'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 5001;  // cAO_Address의 의미
   END_VAR

   cAO_Address := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 5001
   );
   END_TYPE

3. 주석으로 의미 설명
   cAO_Address : UINT := 5001;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:39

설명: cMAX_Address: 초기값 '10001'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 10001;  // cMAX_Address의 의미
   END_VAR

   cMAX_Address := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 10001
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Address : UINT := 10001;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:40

설명: cMAX_Persistent_Address: 초기값 '11001'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 11001;  // cMAX_Persistent_Address의 의미
   END_VAR

   cMAX_Persistent_Address := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 11001
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Persistent_Address : UINT := 11001;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:41

설명: cSX_Address: 초기값 '15001'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 15001;  // cSX_Address의 의미
   END_VAR

   cSX_Address := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 15001
   );
   END_TYPE

3. 주석으로 의미 설명
   cSX_Address : UINT := 15001;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:42

설명: cSX_Persistent_Address: 초기값 '17001'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 17001;  // cSX_Persistent_Address의 의미
   END_VAR

   cSX_Persistent_Address := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 17001
   );
   END_TYPE

3. 주석으로 의미 설명
   cSX_Persistent_Address : UINT := 17001;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:44

설명: cPrecision: 초기값 '3'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 3;  // cPrecision의 의미
   END_VAR

   cPrecision := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 3
   );
   END_TYPE

3. 주석으로 의미 설명
   cPrecision : UINT := 3;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:51

설명: cMAX_Mini8_Input_Channel: 초기값 '30'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 30;  // cMAX_Mini8_Input_Channel의 의미
   END_VAR

   cMAX_Mini8_Input_Channel := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 30
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Mini8_Input_Channel : UINT := 30;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:55

설명: cModBusTCP_Mini8_Port: 초기값 '502'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 502;  // cModBusTCP_Mini8_Port의 의미
   END_VAR

   cModBusTCP_Mini8_Port := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 502
   );
   END_TYPE

3. 주석으로 의미 설명
   cModBusTCP_Mini8_Port : UINT := 502;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:70

설명: cMAX_TC_Channel: 초기값 '36'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 36;  // cMAX_TC_Channel의 의미
   END_VAR

   cMAX_TC_Channel := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 36
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_TC_Channel : UINT := 36;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:71

설명: cMAX_CJC_Channel: 초기값 '12'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 12;  // cMAX_CJC_Channel의 의미
   END_VAR

   cMAX_CJC_Channel := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 12
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_CJC_Channel : UINT := 12;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:72

설명: cMAX_Version_Channel: 초기값 '3'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 3;  // cMAX_Version_Channel의 의미
   END_VAR

   cMAX_Version_Channel := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 3
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Version_Channel : UINT := 3;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:73

설명: cMAX_OutPut_Channel: 초기값 '8'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 8;  // cMAX_OutPut_Channel의 의미
   END_VAR

   cMAX_OutPut_Channel := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 8
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_OutPut_Channel : UINT := 8;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:78

설명: cPort_No: 초기값 '502'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 502;  // cPort_No의 의미
   END_VAR

   cPort_No := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 502
   );
   END_TYPE

3. 주석으로 의미 설명
   cPort_No : UINT := 502;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:81

설명: cVG_TimeOut: 초기값 '5'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 5;  // cVG_TimeOut의 의미
   END_VAR

   cVG_TimeOut := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 5
   );
   END_TYPE

3. 주석으로 의미 설명
   cVG_TimeOut : UDINT := 5;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:223

설명: cMFC03_Index: 초기값 '3'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 3;  // cMFC03_Index의 의미
   END_VAR

   cMFC03_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 3
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC03_Index : UINT := 3;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:224

설명: cMFC04_Index: 초기값 '4'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 4;  // cMFC04_Index의 의미
   END_VAR

   cMFC04_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 4
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC04_Index : UINT := 4;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:225

설명: cMFC05_Index: 초기값 '5'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 5;  // cMFC05_Index의 의미
   END_VAR

   cMFC05_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 5
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC05_Index : UINT := 5;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:226

설명: cMFC06_Index: 초기값 '6'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 6;  // cMFC06_Index의 의미
   END_VAR

   cMFC06_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 6
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC06_Index : UINT := 6;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:227

설명: cMFC07_Index: 초기값 '7'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 7;  // cMFC07_Index의 의미
   END_VAR

   cMFC07_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 7
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC07_Index : UINT := 7;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:228

설명: cMFC08_Index: 초기값 '8'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 8;  // cMFC08_Index의 의미
   END_VAR

   cMFC08_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 8
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC08_Index : UINT := 8;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:229

설명: cMFC09_Index: 초기값 '9'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 9;  // cMFC09_Index의 의미
   END_VAR

   cMFC09_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 9
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC09_Index : UINT := 9;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:231

설명: cMFC11_Index: 초기값 '11'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 11;  // cMFC11_Index의 의미
   END_VAR

   cMFC11_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 11
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC11_Index : UINT := 11;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:232

설명: cMFC12_Index: 초기값 '12'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 12;  // cMFC12_Index의 의미
   END_VAR

   cMFC12_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 12
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC12_Index : UINT := 12;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:233

설명: cMFC13_Index: 초기값 '13'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 13;  // cMFC13_Index의 의미
   END_VAR

   cMFC13_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 13
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC13_Index : UINT := 13;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:234

설명: cMFC14_Index: 초기값 '14'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 14;  // cMFC14_Index의 의미
   END_VAR

   cMFC14_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 14
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC14_Index : UINT := 14;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:235

설명: cMFC15_Index: 초기값 '15'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 15;  // cMFC15_Index의 의미
   END_VAR

   cMFC15_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 15
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC15_Index : UINT := 15;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:236

설명: cMFC16_Index: 초기값 '16'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 16;  // cMFC16_Index의 의미
   END_VAR

   cMFC16_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 16
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC16_Index : UINT := 16;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:237

설명: cMFC17_Index: 초기값 '17'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 17;  // cMFC17_Index의 의미
   END_VAR

   cMFC17_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 17
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC17_Index : UINT := 17;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:238

설명: cMFC18_Index: 초기값 '18'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 18;  // cMFC18_Index의 의미
   END_VAR

   cMFC18_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 18
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC18_Index : UINT := 18;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:239

설명: cMFC19_Index: 초기값 '19'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 19;  // cMFC19_Index의 의미
   END_VAR

   cMFC19_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 19
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC19_Index : UINT := 19;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:240

설명: cMFC20_Index: 초기값 '20'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 20;  // cMFC20_Index의 의미
   END_VAR

   cMFC20_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 20
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC20_Index : UINT := 20;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:241

설명: cMFC21_Index: 초기값 '21'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 21;  // cMFC21_Index의 의미
   END_VAR

   cMFC21_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 21
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC21_Index : UINT := 21;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:242

설명: cMFC22_Index: 초기값 '22'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 22;  // cMFC22_Index의 의미
   END_VAR

   cMFC22_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 22
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC22_Index : UINT := 22;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:243

설명: cMFC23_Index: 초기값 '23'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 23;  // cMFC23_Index의 의미
   END_VAR

   cMFC23_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 23
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC23_Index : UINT := 23;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:244

설명: cMFC24_Index: 초기값 '24'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 24;  // cMFC24_Index의 의미
   END_VAR

   cMFC24_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 24
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC24_Index : UINT := 24;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:245

설명: cMFC25_Index: 초기값 '25'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 25;  // cMFC25_Index의 의미
   END_VAR

   cMFC25_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 25
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC25_Index : UINT := 25;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:246

설명: cMFC26_Index: 초기값 '26'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 26;  // cMFC26_Index의 의미
   END_VAR

   cMFC26_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 26
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC26_Index : UINT := 26;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:247

설명: cMFC27_Index: 초기값 '27'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 27;  // cMFC27_Index의 의미
   END_VAR

   cMFC27_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 27
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC27_Index : UINT := 27;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:248

설명: cMFC28_Index: 초기값 '28'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 28;  // cMFC28_Index의 의미
   END_VAR

   cMFC28_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 28
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC28_Index : UINT := 28;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:249

설명: cMFC29_Index: 초기값 '29'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 29;  // cMFC29_Index의 의미
   END_VAR

   cMFC29_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 29
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC29_Index : UINT := 29;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:250

설명: cMFC30_Index: 초기값 '30'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 30;  // cMFC30_Index의 의미
   END_VAR

   cMFC30_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 30
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC30_Index : UINT := 30;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:251

설명: cMFC31_Index: 초기값 '31'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 31;  // cMFC31_Index의 의미
   END_VAR

   cMFC31_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 31
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC31_Index : UINT := 31;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:252

설명: cMFC32_Index: 초기값 '32'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 32;  // cMFC32_Index의 의미
   END_VAR

   cMFC32_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 32
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC32_Index : UINT := 32;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:253

설명: cMFC33_Index: 초기값 '33'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 33;  // cMFC33_Index의 의미
   END_VAR

   cMFC33_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 33
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC33_Index : UINT := 33;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:254

설명: cMFC34_Index: 초기값 '34'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 34;  // cMFC34_Index의 의미
   END_VAR

   cMFC34_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 34
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC34_Index : UINT := 34;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:255

설명: cMFC35_Index: 초기값 '35'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 35;  // cMFC35_Index의 의미
   END_VAR

   cMFC35_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 35
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC35_Index : UINT := 35;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:256

설명: cMFC36_Index: 초기값 '36'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 36;  // cMFC36_Index의 의미
   END_VAR

   cMFC36_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 36
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC36_Index : UINT := 36;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:265

설명: cMFC81_Index: 초기값 '81'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 81;  // cMFC81_Index의 의미
   END_VAR

   cMFC81_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 81
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC81_Index : UINT := 81;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:266

설명: cMFC82_Index: 초기값 '82'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 82;  // cMFC82_Index의 의미
   END_VAR

   cMFC82_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 82
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC82_Index : UINT := 82;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:270

설명: cMFC50_Index: 초기값 '50'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 50;  // cMFC50_Index의 의미
   END_VAR

   cMFC50_Index := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 50
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC50_Index : UINT := 50;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:275

설명: cMFC_CLOSE: 초기값 '3'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 3;  // cMFC_CLOSE의 의미
   END_VAR

   cMFC_CLOSE := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 3
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC_CLOSE : BYTE := 3;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:277

설명: cH2_Low_Flow: 초기값 '1.4'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 1.4;  // cH2_Low_Flow의 의미
   END_VAR

   cH2_Low_Flow := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 1.4
   );
   END_TYPE

3. 주석으로 의미 설명
   cH2_Low_Flow : REAL := 1.4;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:278

설명: cH2_Mid_Flow: 초기값 '3.4'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 3.4;  // cH2_Mid_Flow의 의미
   END_VAR

   cH2_Mid_Flow := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 3.4
   );
   END_TYPE

3. 주석으로 의미 설명
   cH2_Mid_Flow : REAL := 3.4;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:279

설명: cH2_High_Flow: 초기값 '6.9'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 6.9;  // cH2_High_Flow의 의미
   END_VAR

   cH2_High_Flow := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 6.9
   );
   END_TYPE

3. 주석으로 의미 설명
   cH2_High_Flow : REAL := 6.9;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:281

설명: cCDA_Low_Set: 초기값 '20'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 20;  // cCDA_Low_Set의 의미
   END_VAR

   cCDA_Low_Set := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 20
   );
   END_TYPE

3. 주석으로 의미 설명
   cCDA_Low_Set : REAL := 20;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:282

설명: cCDA_Mid_Set: 초기값 '30'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 30;  // cCDA_Mid_Set의 의미
   END_VAR

   cCDA_Mid_Set := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 30
   );
   END_TYPE

3. 주석으로 의미 설명
   cCDA_Mid_Set : REAL := 30;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:283

설명: cCDA_High_Set: 초기값 '40'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 40;  // cCDA_High_Set의 의미
   END_VAR

   cCDA_High_Set := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 40
   );
   END_TYPE

3. 주석으로 의미 설명
   cCDA_High_Set : REAL := 40;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:284

설명: cCDA_Over_Set: 초기값 '50'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 50;  // cCDA_Over_Set의 의미
   END_VAR

   cCDA_Over_Set := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 50
   );
   END_TYPE

3. 주석으로 의미 설명
   cCDA_Over_Set : REAL := 50;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:286

설명: cCDA_Auto_Ramp_Time: 초기값 '600'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 600;  // cCDA_Auto_Ramp_Time의 의미
   END_VAR

   cCDA_Auto_Ramp_Time := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 600
   );
   END_TYPE

3. 주석으로 의미 설명
   cCDA_Auto_Ramp_Time : REAL := 600;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:290

설명: cGauge_AtoD: 초기값 '32767'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 32767;  // cGauge_AtoD의 의미
   END_VAR

   cGauge_AtoD := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 32767
   );
   END_TYPE

3. 주석으로 의미 설명
   cGauge_AtoD : UINT := 32767;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:291

설명: cGauge_Pressure_Min: 초기값 '600'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 600;  // cGauge_Pressure_Min의 의미
   END_VAR

   cGauge_Pressure_Min := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 600
   );
   END_TYPE

3. 주석으로 의미 설명
   cGauge_Pressure_Min : UINT := 600;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:292

설명: cGauge_Pressure_Max: 초기값 '1100'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 1100;  // cGauge_Pressure_Max의 의미
   END_VAR

   cGauge_Pressure_Max := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 1100
   );
   END_TYPE

3. 주석으로 의미 설명
   cGauge_Pressure_Max : UINT := 1100;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:293

설명: cGauge_Unit: 초기값 '133.322368'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 133.322368;  // cGauge_Unit의 의미
   END_VAR

   cGauge_Unit := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 133.322368
   );
   END_TYPE

3. 주석으로 의미 설명
   cGauge_Unit : REAL := 133.322368;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:294

설명: cGauge_Unit_KPa: 초기값 '1000.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 1000.0;  // cGauge_Unit_KPa의 의미
   END_VAR

   cGauge_Unit_KPa := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 1000.0
   );
   END_TYPE

3. 주석으로 의미 설명
   cGauge_Unit_KPa : REAL := 1000.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:295

설명: cGauge_Unit_MPa: 초기값 '1000.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 1000.0;  // cGauge_Unit_MPa의 의미
   END_VAR

   cGauge_Unit_MPa := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 1000.0
   );
   END_TYPE

3. 주석으로 의미 설명
   cGauge_Unit_MPa : REAL := 1000.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:296

설명: cGauge_Swap_Unit: 초기값 '1333'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 1333;  // cGauge_Swap_Unit의 의미
   END_VAR

   cGauge_Swap_Unit := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 1333
   );
   END_TYPE

3. 주석으로 의미 설명
   cGauge_Swap_Unit : REAL := 1333;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:297

설명: cGauge_Swap_Milli: 초기값 '1000.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 1000.0;  // cGauge_Swap_Milli의 의미
   END_VAR

   cGauge_Swap_Milli := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 1000.0
   );
   END_TYPE

3. 주석으로 의미 설명
   cGauge_Swap_Milli : REAL := 1000.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:300

설명: cPPS_to_mm: 초기값 '0.333'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.333;  // cPPS_to_mm의 의미
   END_VAR

   cPPS_to_mm := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.333
   );
   END_TYPE

3. 주석으로 의미 설명
   cPPS_to_mm : REAL := 0.333;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:301

설명: cGauge_Slm_Sccm: 초기값 '1000.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 1000.0;  // cGauge_Slm_Sccm의 의미
   END_VAR

   cGauge_Slm_Sccm := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 1000.0
   );
   END_TYPE

3. 주석으로 의미 설명
   cGauge_Slm_Sccm : REAL := 1000.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:303

설명: cGauge_Swap_VG02: 초기값 '1333'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 1333;  // cGauge_Swap_VG02의 의미
   END_VAR

   cGauge_Swap_VG02 := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 1333
   );
   END_TYPE

3. 주석으로 의미 설명
   cGauge_Swap_VG02 : REAL := 1333;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:304

설명: cGauge_Swap_VG01: 초기값 '400'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 400;  // cGauge_Swap_VG01의 의미
   END_VAR

   cGauge_Swap_VG01 := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 400
   );
   END_TYPE

3. 주석으로 의미 설명
   cGauge_Swap_VG01 : REAL := 400;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:328

설명: cMAX_Size_String: 초기값 '19'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 19;  // cMAX_Size_String의 의미
   END_VAR

   cMAX_Size_String := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 19
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Size_String : UINT := 19;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:329

설명: cMAX_Size_String_2X: 초기값 '40'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 40;  // cMAX_Size_String_2X의 의미
   END_VAR

   cMAX_Size_String_2X := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 40
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Size_String_2X : UINT := 40;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:330

설명: cMAX_Log_Size_String: 초기값 '25'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 25;  // cMAX_Log_Size_String의 의미
   END_VAR

   cMAX_Log_Size_String := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 25
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Log_Size_String : UINT := 25;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:331

설명: cMAX_Mars_Size_String: 초기값 '60'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 60;  // cMAX_Mars_Size_String의 의미
   END_VAR

   cMAX_Mars_Size_String := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 60
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Mars_Size_String : UINT := 60;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:333

설명: cMAX_Recipe_Step: 초기값 '150'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 150;  // cMAX_Recipe_Step의 의미
   END_VAR

   cMAX_Recipe_Step := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 150
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Recipe_Step : UINT := 150;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:334

설명: cMax_Limit_Duplication_Step: 초기값 '500'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 500;  // cMax_Limit_Duplication_Step의 의미
   END_VAR

   cMax_Limit_Duplication_Step := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 500
   );
   END_TYPE

3. 주석으로 의미 설명
   cMax_Limit_Duplication_Step : UINT := 500;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:336

설명: cMAX_RSD_Damper: 초기값 '12'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 12;  // cMAX_RSD_Damper의 의미
   END_VAR

   cMAX_RSD_Damper := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 12
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_RSD_Damper : UINT := 12;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:337

설명: cMAX_Heater_Zone: 초기값 '20'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 20;  // cMAX_Heater_Zone의 의미
   END_VAR

   cMAX_Heater_Zone := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 20
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Heater_Zone : UINT := 20;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:338

설명: cMAX_Heater_Use_Zone: 초기값 '12'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 12;  // cMAX_Heater_Use_Zone의 의미
   END_VAR

   cMAX_Heater_Use_Zone := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 12
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Heater_Use_Zone : UINT := 12;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:339

설명: cMAX_Heater_SCR: 초기값 '12'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 12;  // cMAX_Heater_SCR의 의미
   END_VAR

   cMAX_Heater_SCR := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 12
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Heater_SCR : UINT := 12;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:340

설명: cMAX_Heater_Use_SCR: 초기값 '12'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 12;  // cMAX_Heater_Use_SCR의 의미
   END_VAR

   cMAX_Heater_Use_SCR := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 12
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Heater_Use_SCR : UINT := 12;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:341

설명: cMAX_Heater_PID: 초기값 '6'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 6;  // cMAX_Heater_PID의 의미
   END_VAR

   cMAX_Heater_PID := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 6
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Heater_PID : UINT := 6;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:342

설명: cMAX_Heater_PID_Zone: 초기값 '12'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 12;  // cMAX_Heater_PID_Zone의 의미
   END_VAR

   cMAX_Heater_PID_Zone := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 12
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Heater_PID_Zone : UINT := 12;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:343

설명: cMAX_Heater_Range: 초기값 '6'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 6;  // cMAX_Heater_Range의 의미
   END_VAR

   cMAX_Heater_Range := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 6
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Heater_Range : UINT := 6;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:344

설명: cMAX_Heater_Monitor: 초기값 '3'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 3;  // cMAX_Heater_Monitor의 의미
   END_VAR

   cMAX_Heater_Monitor := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 3
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Heater_Monitor : UINT := 3;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:345

설명: cMAX_Heater_Message: 초기값 '36'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 36;  // cMAX_Heater_Message의 의미
   END_VAR

   cMAX_Heater_Message := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 36
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Heater_Message : UINT := 36;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:347

설명: cMAX_SCR_MainZone: 초기값 '4'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 4;  // cMAX_SCR_MainZone의 의미
   END_VAR

   cMAX_SCR_MainZone := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 4
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_SCR_MainZone : UINT := 4;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:351

설명: cMAX_LineHeater_Zone: 초기값 '54'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 54;  // cMAX_LineHeater_Zone의 의미
   END_VAR

   cMAX_LineHeater_Zone := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 54
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_LineHeater_Zone : UINT := 54;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:352

설명: cMAX_LineHeater_Use_Zone: 초기값 '54'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 54;  // cMAX_LineHeater_Use_Zone의 의미
   END_VAR

   cMAX_LineHeater_Use_Zone := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 54
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_LineHeater_Use_Zone : UINT := 54;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:353

설명: cMAX_LineHeater_Module_Zone: 초기값 '16'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 16;  // cMAX_LineHeater_Module_Zone의 의미
   END_VAR

   cMAX_LineHeater_Module_Zone := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 16
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_LineHeater_Module_Zone : UINT := 16;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:357

설명: cMAX_Alarm: 초기값 '30000'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 30000;  // cMAX_Alarm의 의미
   END_VAR

   cMAX_Alarm := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 30000
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Alarm : UINT := 30000;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:359

설명: cMAX_SubRecipe: 초기값 '50'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 50;  // cMAX_SubRecipe의 의미
   END_VAR

   cMAX_SubRecipe := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 50
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_SubRecipe : UINT := 50;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:360

설명: cMAX_Table: 초기값 '150'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 150;  // cMAX_Table의 의미
   END_VAR

   cMAX_Table := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 150
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Table : UINT := 150;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:362

설명: cMAX_G_LIFE_Gas: 초기값 '50'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 50;  // cMAX_G_LIFE_Gas의 의미
   END_VAR

   cMAX_G_LIFE_Gas := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 50
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_G_LIFE_Gas : UINT := 50;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:365

설명: cMAX_Valve: 초기값 '200'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 200;  // cMAX_Valve의 의미
   END_VAR

   cMAX_Valve := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 200
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Valve : UINT := 200;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:366

설명: cMAX_Gas: 초기값 '99'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 99;  // cMAX_Gas의 의미
   END_VAR

   cMAX_Gas := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 99
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Gas : UINT := 99;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:367

설명: cMAX_PT: 초기값 '130'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 130;  // cMAX_PT의 의미
   END_VAR

   cMAX_PT := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 130
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_PT : UINT := 130;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:368

설명: cMAX_VG: 초기값 '20'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 20;  // cMAX_VG의 의미
   END_VAR

   cMAX_VG := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 20
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_VG : UINT := 20;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:369

설명: cMAX_ECAT_VG: 초기값 '5'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 5;  // cMAX_ECAT_VG의 의미
   END_VAR

   cMAX_ECAT_VG := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 5
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_ECAT_VG : UINT := 5;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:370

설명: cMAX_MFC: 초기값 '150'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 150;  // cMAX_MFC의 의미
   END_VAR

   cMAX_MFC := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 150
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_MFC : UINT := 150;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:373

설명: cMAX_APC: 초기값 '30'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 30;  // cMAX_APC의 의미
   END_VAR

   cMAX_APC := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 30
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_APC : UINT := 30;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:374

설명: cMAX_RSD: 초기값 '12'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 12;  // cMAX_RSD의 의미
   END_VAR

   cMAX_RSD := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 12
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_RSD : UINT := 12;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:377

설명: cMAX_Manometer: 초기값 '50'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 50;  // cMAX_Manometer의 의미
   END_VAR

   cMAX_Manometer := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 50
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Manometer : UINT := 50;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:379

설명: cMAX_PCW: 초기값 '40'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 40;  // cMAX_PCW의 의미
   END_VAR

   cMAX_PCW := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 40
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_PCW : UINT := 40;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:380

설명: cMAX_LSC: 초기값 '20'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 20;  // cMAX_LSC의 의미
   END_VAR

   cMAX_LSC := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 20
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_LSC : UINT := 20;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:381

설명: cMAX_ProcessData: 초기값 '7'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 7;  // cMAX_ProcessData의 의미
   END_VAR

   cMAX_ProcessData := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 7
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_ProcessData : UINT := 7;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:383

설명: cMAX_APC_PID: 초기값 '30'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 30;  // cMAX_APC_PID의 의미
   END_VAR

   cMAX_APC_PID := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 30
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_APC_PID : UINT := 30;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:384

설명: cMAX_APC_LeakCheckCount: 초기값 '20'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 20;  // cMAX_APC_LeakCheckCount의 의미
   END_VAR

   cMAX_APC_LeakCheckCount := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 20
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_APC_LeakCheckCount : UINT := 20;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:385

설명: cMAX_APC_Close_Offset: 초기값 '2.5'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 2.5;  // cMAX_APC_Close_Offset의 의미
   END_VAR

   cMAX_APC_Close_Offset := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 2.5
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_APC_Close_Offset : REAL := 2.5;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:386

설명: cCFG_APC_Offset_Variation: 초기값 '1.01'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 1.01;  // cCFG_APC_Offset_Variation의 의미
   END_VAR

   cCFG_APC_Offset_Variation := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 1.01
   );
   END_TYPE

3. 주석으로 의미 설명
   cCFG_APC_Offset_Variation : REAL := 1.01;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:389

설명: cMAX_Collection_Item: 초기값 '2000'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 2000;  // cMAX_Collection_Item의 의미
   END_VAR

   cMAX_Collection_Item := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 2000
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Collection_Item : UINT := 2000;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:391

설명: cMAX_LV_Log_Size: 초기값 '101'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 101;  // cMAX_LV_Log_Size의 의미
   END_VAR

   cMAX_LV_Log_Size := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 101
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_LV_Log_Size : UINT := 101;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:392

설명: cMAX_Log_Item: 초기값 '2000'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 2000;  // cMAX_Log_Item의 의미
   END_VAR

   cMAX_Log_Item := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 2000
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Log_Item : UINT := 2000;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:394

설명: cMAX_Log_Dcoll_Max_Item: 초기값 '1700'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 1700;  // cMAX_Log_Dcoll_Max_Item의 의미
   END_VAR

   cMAX_Log_Dcoll_Max_Item := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 1700
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Log_Dcoll_Max_Item : UINT := 1700;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:395

설명: cMAX_Log_Dcoll_Msg_Sum: 초기값 '120'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 120;  // cMAX_Log_Dcoll_Msg_Sum의 의미
   END_VAR

   cMAX_Log_Dcoll_Msg_Sum := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 120
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Log_Dcoll_Msg_Sum : UINT := 120;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:396

설명: cMAX_Log_Para_Item: 초기값 '17'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 17;  // cMAX_Log_Para_Item의 의미
   END_VAR

   cMAX_Log_Para_Item := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 17
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Log_Para_Item : UINT := 17;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:397

설명: cMAX_Log_LV_Msg_Sum: 초기값 '20'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 20;  // cMAX_Log_LV_Msg_Sum의 의미
   END_VAR

   cMAX_Log_LV_Msg_Sum := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 20
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Log_LV_Msg_Sum : UINT := 20;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:399

설명: cMAX_Event_Log_Buffer: 초기값 '500'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 500;  // cMAX_Event_Log_Buffer의 의미
   END_VAR

   cMAX_Event_Log_Buffer := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 500
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Event_Log_Buffer : UINT := 500;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:401

설명: cMAX_Mars_Info: 초기값 '20'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 20;  // cMAX_Mars_Info의 의미
   END_VAR

   cMAX_Mars_Info := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 20
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Mars_Info : UINT := 20;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:405

설명: cMAX_HW_ALARM_SIZE: 초기값 '200'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 200;  // cMAX_HW_ALARM_SIZE의 의미
   END_VAR

   cMAX_HW_ALARM_SIZE := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 200
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_HW_ALARM_SIZE : UINT := 200;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:407

설명: cMAX_SLAVES: 초기값 '44'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 44;  // cMAX_SLAVES의 의미
   END_VAR

   cMAX_SLAVES := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 44
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_SLAVES : UINT := 44;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:409

설명: cMAX_Rate: 초기값 '3'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 3;  // cMAX_Rate의 의미
   END_VAR

   cMAX_Rate := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 3
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Rate : UINT := 3;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:411

설명: cMAX_Rate_Config: 초기값 '5'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 5;  // cMAX_Rate_Config의 의미
   END_VAR

   cMAX_Rate_Config := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 5
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Rate_Config : UINT := 5;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:414

설명: cMAX_TV_UseCount: 초기값 '8'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 8;  // cMAX_TV_UseCount의 의미
   END_VAR

   cMAX_TV_UseCount := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 8
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_TV_UseCount : UINT := 8;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:416

설명: cMAX_AUTO_TV_CTRL: 초기값 '3'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 3;  // cMAX_AUTO_TV_CTRL의 의미
   END_VAR

   cMAX_AUTO_TV_CTRL := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 3
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_AUTO_TV_CTRL : UINT := 3;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:417

설명: cCFG_Zone_Center: 초기값 '7'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 7;  // cCFG_Zone_Center의 의미
   END_VAR

   cCFG_Zone_Center := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 7
   );
   END_TYPE

3. 주석으로 의미 설명
   cCFG_Zone_Center : UINT := 7;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:419

설명: cMAX_FRP_Speed: 초기값 '60'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 60;  // cMAX_FRP_Speed의 의미
   END_VAR

   cMAX_FRP_Speed := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 60
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_FRP_Speed : REAL := 60;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:421

설명: cMAX_LV_Monitor: 초기값 '7'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 7;  // cMAX_LV_Monitor의 의미
   END_VAR

   cMAX_LV_Monitor := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 7
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_LV_Monitor : UINT := 7;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:425

설명: cMAX_FFU: 초기값 '6'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 6;  // cMAX_FFU의 의미
   END_VAR

   cMAX_FFU := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 6
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_FFU : UINT := 6;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:426

설명: cMAX_BIP: 초기값 '20'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 20;  // cMAX_BIP의 의미
   END_VAR

   cMAX_BIP := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 20
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_BIP : UINT := 20;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:428

설명: cMfcFlowCheckBand: 초기값 '2.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 2.0;  // cMfcFlowCheckBand의 의미
   END_VAR

   cMfcFlowCheckBand := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 2.0
   );
   END_TYPE

3. 주석으로 의미 설명
   cMfcFlowCheckBand : REAL := 2.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:429

설명: cMAX_Recipe_Maintenance: 초기값 '18'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 18;  // cMAX_Recipe_Maintenance의 의미
   END_VAR

   cMAX_Recipe_Maintenance := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 18
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_Recipe_Maintenance : UINT := 18;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:431

설명: cMAX_E5GC01: 초기값 '7'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 7;  // cMAX_E5GC01의 의미
   END_VAR

   cMAX_E5GC01 := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 7
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_E5GC01 : UINT := 7;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:439

설명: cCFG_LH_Clean_Temp: 초기값 '25'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 25;  // cCFG_LH_Clean_Temp의 의미
   END_VAR

   cCFG_LH_Clean_Temp := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 25
   );
   END_TYPE

3. 주석으로 의미 설명
   cCFG_LH_Clean_Temp : REAL := 25;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:441

설명: cUnloadTimeOut: 초기값 '3600'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 3600;  // cUnloadTimeOut의 의미
   END_VAR

   cUnloadTimeOut := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 3600
   );
   END_TYPE

3. 주석으로 의미 설명
   cUnloadTimeOut : UINT := 3600;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:443

설명: cBoat_Single_boundary_Speed: 초기값 '50'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 50;  // cBoat_Single_boundary_Speed의 의미
   END_VAR

   cBoat_Single_boundary_Speed := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 50
   );
   END_TYPE

3. 주석으로 의미 설명
   cBoat_Single_boundary_Speed : REAL := 50;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:444

설명: cBoat_Single_boundary_Position: 초기값 '2000'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 2000;  // cBoat_Single_boundary_Position의 의미
   END_VAR

   cBoat_Single_boundary_Position := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 2000
   );
   END_TYPE

3. 주석으로 의미 설명
   cBoat_Single_boundary_Position : REAL := 2000;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:448

설명: cMFC_Dec_Start: 초기값 '91'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 91;  // cMFC_Dec_Start의 의미
   END_VAR

   cMFC_Dec_Start := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 91
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC_Dec_Start : UINT := 91;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:449

설명: cMFC_Dec_End: 초기값 '194'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 194;  // cMFC_Dec_End의 의미
   END_VAR

   cMFC_Dec_End := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 194
   );
   END_TYPE

3. 주석으로 의미 설명
   cMFC_Dec_End : UINT := 194;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:453

설명: cVG_Dec_Start: 초기값 '161'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 161;  // cVG_Dec_Start의 의미
   END_VAR

   cVG_Dec_Start := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 161
   );
   END_TYPE

3. 주석으로 의미 설명
   cVG_Dec_Start : UINT := 161;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:454

설명: cVG_Dec_End: 초기값 '169'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 169;  // cVG_Dec_End의 의미
   END_VAR

   cVG_Dec_End := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 169
   );
   END_TYPE

3. 주석으로 의미 설명
   cVG_Dec_End : UINT := 169;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:456

설명: cPT_Dec_Start: 초기값 '171'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 171;  // cPT_Dec_Start의 의미
   END_VAR

   cPT_Dec_Start := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 171
   );
   END_TYPE

3. 주석으로 의미 설명
   cPT_Dec_Start : UINT := 171;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:457

설명: cPT_Dec_End: 초기값 '199'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 199;  // cPT_Dec_End의 의미
   END_VAR

   cPT_Dec_End := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 199
   );
   END_TYPE

3. 주석으로 의미 설명
   cPT_Dec_End : UINT := 199;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:459

설명: cAPC_iMode_LogNum: 초기값 '231'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 231;  // cAPC_iMode_LogNum의 의미
   END_VAR

   cAPC_iMode_LogNum := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 231
   );
   END_TYPE

3. 주석으로 의미 설명
   cAPC_iMode_LogNum : UINT := 231;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:460

설명: cAPC_oMode_LogNum: 초기값 '232'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 232;  // cAPC_oMode_LogNum의 의미
   END_VAR

   cAPC_oMode_LogNum := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 232
   );
   END_TYPE

3. 주석으로 의미 설명
   cAPC_oMode_LogNum : UINT := 232;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:462

설명: cFRP_oMode_LogNum: 초기값 '311'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 311;  // cFRP_oMode_LogNum의 의미
   END_VAR

   cFRP_oMode_LogNum := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 311
   );
   END_TYPE

3. 주석으로 의미 설명
   cFRP_oMode_LogNum : UINT := 311;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:464

설명: cAPC_PID_STEP: 초기값 '200'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 200;  // cAPC_PID_STEP의 의미
   END_VAR

   cAPC_PID_STEP := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 200
   );
   END_TYPE

3. 주석으로 의미 설명
   cAPC_PID_STEP : BYTE := 200;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:465

설명: cAPC_SLOW_PID_STEP: 초기값 '150'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 150;  // cAPC_SLOW_PID_STEP의 의미
   END_VAR

   cAPC_SLOW_PID_STEP := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 150
   );
   END_TYPE

3. 주석으로 의미 설명
   cAPC_SLOW_PID_STEP : BYTE := 150;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:467

설명: cAPC_PID_CH: 초기값 '3.5'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 3.5;  // cAPC_PID_CH의 의미
   END_VAR

   cAPC_PID_CH := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 3.5
   );
   END_TYPE

3. 주석으로 의미 설명
   cAPC_PID_CH : REAL := 3.5;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:468

설명: cAPC_PID_CL: 초기값 '0.5'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.5;  // cAPC_PID_CL의 의미
   END_VAR

   cAPC_PID_CL := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.5
   );
   END_TYPE

3. 주석으로 의미 설명
   cAPC_PID_CL : REAL := 0.5;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:471

설명: cITK_Boat_Open_Temp: 초기값 '650.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 650.0;  // cITK_Boat_Open_Temp의 의미
   END_VAR

   cITK_Boat_Open_Temp := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 650.0
   );
   END_TYPE

3. 주석으로 의미 설명
   cITK_Boat_Open_Temp : REAL := 650.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:473

설명: cITK_PT_Pressure: 초기값 '0.1'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 0.1;  // cITK_PT_Pressure의 의미
   END_VAR

   cITK_PT_Pressure := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 0.1
   );
   END_TYPE

3. 주석으로 의미 설명
   cITK_PT_Pressure : REAL := 0.1;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:475

설명: cITK_CM2_Pressure: 초기값 '780.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 780.0;  // cITK_CM2_Pressure의 의미
   END_VAR

   cITK_CM2_Pressure := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 780.0
   );
   END_TYPE

3. 주석으로 의미 설명
   cITK_CM2_Pressure : REAL := 780.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:476

설명: cITK_CM3_Pressure: 초기값 '780.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 780.0;  // cITK_CM3_Pressure의 의미
   END_VAR

   cITK_CM3_Pressure := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 780.0
   );
   END_TYPE

3. 주석으로 의미 설명
   cITK_CM3_Pressure : REAL := 780.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:477

설명: cITK_CM4_Pressure: 초기값 '10000.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 10000.0;  // cITK_CM4_Pressure의 의미
   END_VAR

   cITK_CM4_Pressure := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 10000.0
   );
   END_TYPE

3. 주석으로 의미 설명
   cITK_CM4_Pressure : REAL := 10000.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:478

설명: cITK_CM5_Pressure: 초기값 '780.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 780.0;  // cITK_CM5_Pressure의 의미
   END_VAR

   cITK_CM5_Pressure := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 780.0
   );
   END_TYPE

3. 주석으로 의미 설명
   cITK_CM5_Pressure : REAL := 780.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:479

설명: cITK_CM6_Pressure: 초기값 '780.0'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 780.0;  // cITK_CM6_Pressure의 의미
   END_VAR

   cITK_CM6_Pressure := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 780.0
   );
   END_TYPE

3. 주석으로 의미 설명
   cITK_CM6_Pressure : REAL := 780.0;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:481

설명: cMAX_SMS_RMS_Use: 초기값 '20'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 20;  // cMAX_SMS_RMS_Use의 의미
   END_VAR

   cMAX_SMS_RMS_Use := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 20
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_SMS_RMS_Use : UINT := 20;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:482

설명: cMAX_SMS_AVG_Use: 초기값 '20'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 20;  // cMAX_SMS_AVG_Use의 의미
   END_VAR

   cMAX_SMS_AVG_Use := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 20
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_SMS_AVG_Use : UINT := 20;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:484

설명: cMAX_PartsLog: 초기값 '60'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 60;  // cMAX_PartsLog의 의미
   END_VAR

   cMAX_PartsLog := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 60
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_PartsLog : UINT := 60;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:485

설명: cMAX_PartsItem: 초기값 '40'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 40;  // cMAX_PartsItem의 의미
   END_VAR

   cMAX_PartsItem := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 40
   );
   END_TYPE

3. 주석으로 의미 설명
   cMAX_PartsItem : UINT := 40;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:486

설명: cParts_RunTime: 초기값 '9'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 9;  // cParts_RunTime의 의미
   END_VAR

   cParts_RunTime := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 9
   );
   END_TYPE

3. 주석으로 의미 설명
   cParts_RunTime : UINT := 9;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:489

설명: cParts_SerialNumber: 초기값 '4'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 4;  // cParts_SerialNumber의 의미
   END_VAR

   cParts_SerialNumber := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 4
   );
   END_TYPE

3. 주석으로 의미 설명
   cParts_SerialNumber : UINT := 4;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:490

설명: cParts_GasSymbol: 초기값 '12'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 12;  // cParts_GasSymbol의 의미
   END_VAR

   cParts_GasSymbol := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 12
   );
   END_TYPE

3. 주석으로 의미 설명
   cParts_GasSymbol : UINT := 12;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA007] 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Constant.TcGVL:491

설명: cParts_FullScale: 초기값 '14'의 의미가 불분명함

⚠️ 위험성:

매직 넘버(의미 불명확한 숫자 상수)는 다음 문제를 야기합니다: - 코드 의도 파악 어려움 (3은 무엇을 의미?) - 유지보수 시 숫자 변경 누락 위험 - 같은 값을 여러 곳에서 다르게 수정 가능 - 코드 리뷰 시 검증 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수로 정의하여 의미 명확화
   VAR CONSTANT
       MAX_RETRY_COUNT : INT := 14;  // cParts_FullScale의 의미
   END_VAR

   cParts_FullScale := MAX_RETRY_COUNT;

2. 열거형 사용 (의미 있는 값들)
   TYPE E_Status :
   (
       IDLE := 0,
       RUNNING := 1,
       ERROR := 14
   );
   END_TYPE

3. 주석으로 의미 설명
   cParts_FullScale : UINT := 14;  // 최대 재시도 횟수

예시:

❌ 나쁜 예:
timeout : INT := 500; // 500이 무엇?
speed := 75; // 75는 무슨 단위?

✅ 좋은 예:
VAR CONSTANT
MOTOR_TIMEOUT_MS : INT := 500; // 모터 타임아웃 500ms
NORMAL_SPEED_PERCENT : INT := 75; // 정상 속도 75%
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:2967

설명: DX_Heater_Profile_Tune_End_Condition: BOOL 변수는 'is', 'has' 등의 접두사 사용 권장 (예: isRunning)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: isDX_Heater_Profile_Tune_End_Condition

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3812

설명: fbGetCurTaskIdx: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gFbGetCurTaskIdx

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3813

설명: nCycleTime: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gNCycleTime

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3815

설명: DX_Tune_Count_Reset: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDX_Tune_Count_Reset

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3818

설명: DI_Heater_Power_Module: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDI_Heater_Power_Module

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3819

설명: DI_Heater_AI01_Module: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDI_Heater_AI01_Module

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3820

설명: DI_Heater_AI02_Module: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDI_Heater_AI02_Module

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3821

설명: DI_Heater_AI03_Module: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDI_Heater_AI03_Module

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3822

설명: DI_Heater_AI04_Module: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDI_Heater_AI04_Module

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3823

설명: DI_Heater_AI05_Module: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDI_Heater_AI05_Module

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3824

설명: DI_Heater_AI06_Module: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDI_Heater_AI06_Module

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3824

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 10개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 10개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3825

설명: DI_Heater_AI07_Module: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDI_Heater_AI07_Module

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3825

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 11개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 11개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3826

설명: DI_Heater_AO01_Module: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDI_Heater_AO01_Module

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3826

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 12개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 12개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3827

설명: DI_Heater_AO02_Module: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDI_Heater_AO02_Module

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3827

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 13개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 13개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3829

설명: DI_Spike_Sensor_Break: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDI_Spike_Sensor_Break

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3829

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 14개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 14개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3830

설명: DI_Profile_Sensor_Break: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDI_Profile_Sensor_Break

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3830

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 15개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 15개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3831

설명: DI_OverTemp_Sensor_Break: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDI_OverTemp_Sensor_Break

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3831

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 16개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 16개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3833

설명: DO_CAS_Mode: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDO_CAS_Mode

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3833

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 17개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 17개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3834

설명: DO_CAS_Mode_Result: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDO_CAS_Mode_Result

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3834

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 18개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 18개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3836

설명: AI_Spike_Temp: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Spike_Temp

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA013] 전역 변수 과다 사용

카테고리: 아키텍처

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3836

설명: D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL: 전역 변수 19개 (권장: 10개 이하)

⚠️ 위험성:

전역 변수 과다 사용은 다음 문제를 야기합니다: - 결합도(Coupling) 증가 - 코드 추적 및 디버깅 어려움 - 의도치 않은 값 변경 위험 - 재사용성 저하 - 테스트 어려움 (모든 전역 상태 고려) - 동시성 문제 (여러 FB에서 접근)
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Function Block 내부 변수로 캡슐화
   FUNCTION_BLOCK FB_Controller
       VAR
           internalState : INT;  // 전역 변수 대신
           sensorValue : REAL;
       END_VAR

       VAR_INPUT
           enable : BOOL;  // 외부 입력
       END_VAR

       VAR_OUTPUT
           status : INT;   // 외부 출력
       END_VAR
   END_FUNCTION_BLOCK

2. 구조체로 관련 변수 그룹화
   TYPE ST_SystemConfig :
   STRUCT
       maxSpeed : REAL;
       timeout : TIME;
       retryCount : INT;
   END_STRUCT
   END_TYPE

   VAR_GLOBAL
       gConfig : ST_SystemConfig;  // 여러 변수 → 하나의 구조체
   END_VAR

3. Property 사용 (TwinCAT 3)
   FUNCTION_BLOCK FB_Data
       VAR PRIVATE
           _value : INT;
       END_VAR

       PROPERTY Value : INT
           GET
               Value := _value;
           SET
               _value := Value;
   END_FUNCTION_BLOCK

4. 필요한 경우에만 전역 변수 사용
   - 시스템 전체 설정
   - HMI 통신 변수
   - 안전 관련 상태

현재 파일의 전역 변수 수: 19개
권장: Function Block으로 리팩토링

예시:

❌ 나쁜 예 (전역 변수 과다):
VAR_GLOBAL
gMotorSpeed : REAL;
gMotorCurrent : REAL;
gMotorTemp : REAL;
gMotorStatus : INT;
gMotorError : BOOL;
// ... 20개 이상
END_VAR

✅ 좋은 예 (캡슐화):
FUNCTION_BLOCK FB_Motor
VAR
speed : REAL;
current : REAL;
temperature : REAL;
END_VAR
END_FUNCTION_BLOCK

VAR_GLOBAL
gMotor : FB_Motor; // 하나의 인스턴스
END_VAR
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3837

설명: AI_Profile_Temp: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Profile_Temp

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3838

설명: AI_Over_Temp: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Over_Temp

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3841

설명: AO_SCR_Set_value: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_SCR_Set_value

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3842

설명: AO_BRC_RDNP: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_BRC_RDNP

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3843

설명: AO_BRC_SP_Lag: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_BRC_SP_Lag

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3844

설명: AO_BRC_Ramping: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_BRC_Ramping

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3845

설명: AO_BRC_WSO: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_BRC_WSO

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3847

설명: AO_CAS_Target_Dev: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_CAS_Target_Dev

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3848

설명: AO_CAS_Target_Result: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_CAS_Target_Result

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3849

설명: AO_CAS_Ratio_Set: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_CAS_Ratio_Set

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3850

설명: AO_CAS_Ratio_Result: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_CAS_Ratio_Result

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3851

설명: AO_CAS_Ratio_Cal_Set: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_CAS_Ratio_Cal_Set

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3852

설명: AI_CAS_Tune_Result: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_CAS_Tune_Result

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3854

설명: DO_Heater_PID_AT_Run: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDO_Heater_PID_AT_Run

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3855

설명: DO_Heater_Power_OnOff: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDO_Heater_Power_OnOff

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3859

설명: AO_AWC_S_Time: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_AWC_S_Time

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3860

설명: AO_AWC_Ramp1: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_AWC_Ramp1

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3861

설명: AO_AWC_Ramp2: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_AWC_Ramp2

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3862

설명: AO_AWC_D_Time: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_AWC_D_Time

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3863

설명: AO_AWC_Factor: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_AWC_Factor

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3864

설명: AO_AWC_Offset: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_AWC_Offset

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3868

설명: AO_Heater_Buff_SP_Change_ITD: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_Heater_Buff_SP_Change_ITD

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3869

설명: AO_Heater_Buff_Ramp_Up_ITD: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_Heater_Buff_Ramp_Up_ITD

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3870

설명: AO_Heater_Buff_Ramp_Down_ITD: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAO_Heater_Buff_Ramp_Down_ITD

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3872

설명: SX_INF_LogName: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_INF_LogName

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3873

설명: SX_INF_DcollLogName: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_INF_DcollLogName

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3874

설명: SX_INF_Message: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_INF_Message

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3875

설명: SX_INF_Sub_Message: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_INF_Sub_Message

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3877

설명: SX_INF_ParaLogName: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_INF_ParaLogName

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3879

설명: SX_INF_LogName_CTC: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_INF_LogName_CTC

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3880

설명: SX_INF_DcollLogName_CTC: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_INF_DcollLogName_CTC

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3881

설명: SX_INF_ParaLogName_CTC: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_INF_ParaLogName_CTC

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3883

설명: SX_Recipe_FullName: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_Recipe_FullName

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3885

설명: SX_PID_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_PID_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3886

설명: DX_PID_Num: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDX_PID_Num

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3887

설명: SX_RDNP_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_RDNP_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3888

설명: SX_Profile_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_Profile_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3889

설명: SX_Calibration_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_Calibration_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3890

설명: SX_ITD_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_ITD_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3891

설명: SX_PowerTrim_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_PowerTrim_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3892

설명: SX_AT_PID_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_AT_PID_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3893

설명: SX_AT_Profile_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_AT_Profile_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3894

설명: SX_AT_Temp_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_AT_Temp_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3895

설명: SX_Alarm_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_Alarm_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3896

설명: SX_APC_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_APC_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3897

설명: SX_LH_Set_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_LH_Set_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3898

설명: SX_LH_Alarm_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_LH_Alarm_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3899

설명: SX_RSD_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_RSD_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3900

설명: SX_FRPTV_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_FRPTV_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3901

설명: SX_FFU_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_FFU_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3902

설명: SX_AWC_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_AWC_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3903

설명: SX_TempTarget_File: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_TempTarget_File

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3905

설명: Log_Title: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gLog_Title

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3906

설명: Log_RealData: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gLog_RealData

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3907

설명: Log_Trend: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gLog_Trend

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3908

설명: Mars_S_Trend: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gMars_S_Trend

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3909

설명: Mars_E_Trend: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gMars_E_Trend

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3911

설명: Para_Log_Data: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPara_Log_Data

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3913

설명: DX_INF_Dcoll_Log: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDX_INF_Dcoll_Log

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3914

설명: DX_INF_Para_Log: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDX_INF_Para_Log

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3916

설명: DX_INF_FRP_End_Condition: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDX_INF_FRP_End_Condition

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3919

설명: AI_Dnet_MFC01_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC01_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3920

설명: AI_Dnet_MFC02_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC02_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3921

설명: AI_Dnet_MFC03_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC03_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3922

설명: AI_Dnet_MFC04_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC04_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3924

설명: AI_Dnet_MFC05_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC05_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3925

설명: AI_Dnet_MFC06_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC06_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3926

설명: AI_Dnet_MFC07_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC07_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3927

설명: AI_Dnet_MFC08_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC08_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3929

설명: AI_Dnet_MFC09_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC09_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3930

설명: AI_Dnet_MFC10_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC10_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3931

설명: AI_Dnet_MFC11_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC11_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3932

설명: AI_Dnet_MFC12_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC12_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3934

설명: AI_Dnet_MFC13_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC13_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3935

설명: AI_Dnet_MFC14_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC14_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3936

설명: AI_Dnet_MFC15_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC15_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3938

설명: AI_Dnet_MFC16_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC16_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3939

설명: AI_Dnet_MFC17_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC17_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3940

설명: AI_Dnet_MFC18_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC18_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3941

설명: AI_Dnet_MFC19_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC19_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3943

설명: AI_Dnet_MFC20_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC20_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3944

설명: AI_Dnet_MFC21_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC21_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3945

설명: AI_Dnet_MFC22_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC22_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3946

설명: AI_Dnet_MFC23_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC23_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3948

설명: AI_Dnet_MFC24_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC24_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3949

설명: AI_Dnet_MFC25_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC25_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3951

설명: AI_Dnet_MFC41_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC41_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3952

설명: AI_Dnet_MFC42_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC42_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3953

설명: AI_Dnet_MFC43_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC43_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3954

설명: AI_Dnet_MFC44_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC44_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3955

설명: AI_Dnet_MFC45_RAMPING_TIME: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC45_RAMPING_TIME

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3957

설명: AI_Dnet_MFC01_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC01_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3958

설명: AI_Dnet_MFC02_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC02_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3959

설명: AI_Dnet_MFC03_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC03_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3960

설명: AI_Dnet_MFC04_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC04_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3962

설명: AI_Dnet_MFC05_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC05_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3963

설명: AI_Dnet_MFC06_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC06_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3964

설명: AI_Dnet_MFC07_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC07_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3965

설명: AI_Dnet_MFC08_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC08_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3967

설명: AI_Dnet_MFC09_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC09_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3968

설명: AI_Dnet_MFC10_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC10_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3969

설명: AI_Dnet_MFC11_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC11_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3970

설명: AI_Dnet_MFC12_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC12_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3972

설명: AI_Dnet_MFC13_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC13_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3973

설명: AI_Dnet_MFC14_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC14_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3974

설명: AI_Dnet_MFC15_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC15_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3975

설명: AI_Dnet_MFC16_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC16_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3977

설명: AI_Dnet_MFC17_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC17_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3978

설명: AI_Dnet_MFC18_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC18_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3979

설명: AI_Dnet_MFC19_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC19_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3980

설명: AI_Dnet_MFC20_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC20_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3982

설명: AI_Dnet_MFC21_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC21_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3983

설명: AI_Dnet_MFC22_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC22_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3984

설명: AI_Dnet_MFC23_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC23_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3985

설명: AI_Dnet_MFC24_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC24_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3987

설명: AI_Dnet_MFC25_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC25_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3989

설명: AI_Dnet_MFC41_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC41_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3990

설명: AI_Dnet_MFC42_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC42_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3991

설명: AI_Dnet_MFC43_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC43_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3992

설명: AI_Dnet_MFC44_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC44_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3993

설명: AI_Dnet_MFC45_FULL_SCALE: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_Dnet_MFC45_FULL_SCALE

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3995

설명: DI_LH_Power: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDI_LH_Power

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3997

설명: DI_Pump_Power: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDI_Pump_Power

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:3999

설명: Sprae_Alarm: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSprae_Alarm

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4001

설명: pLog: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPLog

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4003

설명: Heater_Power: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gHeater_Power

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4005

설명: STS_EMG_Trig: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSTS_EMG_Trig

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4006

설명: Old_Temp_PowerLimit: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gOld_Temp_PowerLimit

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4007

설명: STS_Temp_PowerLimit: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSTS_Temp_PowerLimit

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4009

설명: SX_MaterialID: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_MaterialID

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4010

설명: SX_SlotNO: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_SlotNO

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4011

설명: SX_LotID: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_LotID

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4013

설명: pALM: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPALM

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4015

설명: pRecipe: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPRecipe

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4016

설명: pSubRecipe: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPSubRecipe

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4017

설명: pVariableRecipe: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPVariableRecipe

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4019

설명: pAbortRecipe: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPAbortRecipe

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4020

설명: pAbortRecipe_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPAbortRecipe_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4022

설명: pHeater_PID: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_PID

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4023

설명: pHeater_PID_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_PID_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4025

설명: pCAL_PID: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPCAL_PID

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4026

설명: pCAL_PID_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPCAL_PID_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4028

설명: pHeater_Profile: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_Profile

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4029

설명: pHeater_Profile_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_Profile_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4030

설명: pHeater_Profile_Tuned: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_Profile_Tuned

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4032

설명: pProfile_Tune: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPProfile_Tune

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4033

설명: pProfile_Tune_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPProfile_Tune_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4035

설명: pHeater_Cal: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_Cal

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4036

설명: pHeater_Cal_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_Cal_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4038

설명: pHeater_RDNP: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_RDNP

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4039

설명: pHeater_RDNP_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_RDNP_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4040

설명: pHeater_RDNP_Tuned: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_RDNP_Tuned

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4042

설명: pRDNP_Tune: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPRDNP_Tune

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4043

설명: pRDNP_Tune_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPRDNP_Tune_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4045

설명: pHeater_Trim: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_Trim

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4046

설명: pHeater_Trim_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_Trim_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4048

설명: pHeater_ITD: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_ITD

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4049

설명: pHeater_ITD_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_ITD_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4051

설명: pHeater_Sub: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_Sub

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4052

설명: pHeater_Sub_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_Sub_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4054

설명: pLH_Alarm: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPLH_Alarm

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4055

설명: pLH_Alarm_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPLH_Alarm_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4057

설명: pLH_Set: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPLH_Set

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4058

설명: pLH_Set_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPLH_Set_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4060

설명: pHeater_Alarm: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_Alarm

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4061

설명: pHeater_Alarm_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_Alarm_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4063

설명: pGas_Alarm: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPGas_Alarm

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4064

설명: pGas_Alarm_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPGas_Alarm_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4066

설명: pPressure_Alarm: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPPressure_Alarm

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4067

설명: pPressure_Alarm_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPPressure_Alarm_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4069

설명: pIntensity_Alarm: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPIntensity_Alarm

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4070

설명: pIntensity_Alarm_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPIntensity_Alarm_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4072

설명: pAlarm: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPAlarm

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4073

설명: pAlarm_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPAlarm_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4075

설명: pRSD: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPRSD

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4076

설명: pRSD_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPRSD_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4078

설명: pFRPTV: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPFRPTV

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4079

설명: pFRPTV_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPFRPTV_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4081

설명: pFFU: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPFFU

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4082

설명: pFFU_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPFFU_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4084

설명: pHeater_AWC: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_AWC

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4085

설명: pHeater_AWC_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPHeater_AWC_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4087

설명: pTempTarget: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPTempTarget

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4088

설명: pTempTarget_Param: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPTempTarget_Param

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4090

설명: pPartsPara: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPPartsPara

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4091

설명: pPartsPara_Trig: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gPPartsPara_Trig

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4098

설명: AX_PHY_Boat_Single_Speed: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAX_PHY_Boat_Single_Speed

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4100

설명: AX_PHY_Boat_Multi_Speed1: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAX_PHY_Boat_Multi_Speed1

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4101

설명: AX_PHY_Boat_Multi_Speed2: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAX_PHY_Boat_Multi_Speed2

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4102

설명: AX_PHY_Boat_Multi_Speed3: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAX_PHY_Boat_Multi_Speed3

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4103

설명: AX_PHY_Boat_Multi_Speed4: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAX_PHY_Boat_Multi_Speed4

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4104

설명: AX_PHY_Boat_Multi_Speed5: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAX_PHY_Boat_Multi_Speed5

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4105

설명: AX_PHY_Boat_Up_Speed: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAX_PHY_Boat_Up_Speed

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4107

설명: AX_INF_Current_AbortAlarm: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAX_INF_Current_AbortAlarm

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4109

설명: AX_CRC16_Table: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAX_CRC16_Table

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4111

설명: Event_Log_Msg: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gEvent_Log_Msg

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4112

설명: Event_Msg_Old: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gEvent_Msg_Old

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4113

설명: Event_Last_Msg: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gEvent_Last_Msg

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4114

설명: Event_Msg_Buff: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gEvent_Msg_Buff

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4115

설명: Event_Log_Path: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gEvent_Log_Path

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4117

설명: SX_INF_MARS_S_Message: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_INF_MARS_S_Message

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4118

설명: SX_INF_MARS_E_Message: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_INF_MARS_E_Message

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4120

설명: SX_INF_MARS_BE_Message: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_INF_MARS_BE_Message

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4121

설명: SX_INF_MARS_BR_Message: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gSX_INF_MARS_BR_Message

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4122

설명: Log_LV_Title: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gLog_LV_Title

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4123

설명: Log_LV_Data: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gLog_LV_Data

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4124

설명: mLV_Log_Path: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gMLV_Log_Path

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4127

설명: BOAT_ELEVATOR_SERVO_ALARM: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gBOAT_ELEVATOR_SERVO_ALARM

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4129

설명: BOAT_ROTATE_ALARM: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gBOAT_ROTATE_ALARM

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4131

설명: DO_Spare_Valve: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDO_Spare_Valve

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4133

설명: DX_Auto_FRP_Mode: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDX_Auto_FRP_Mode

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4135

설명: DX_Boat_Up_BRC_Mode: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDX_Boat_Up_BRC_Mode

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4138

설명: AX_LoadingIndex: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAX_LoadingIndex

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4140

설명: DX_FF_MV_Usable: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDX_FF_MV_Usable

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4141

설명: DX_FF_Reset: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDX_FF_Reset

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4142

설명: ProcessLog_Interval: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gProcessLog_Interval

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4144

설명: AI_VG_Pressure: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gAI_VG_Pressure

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4146

설명: DX_VG_Check: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDX_VG_Check

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA012] 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Global Variables\Global_Variables_Memory.TcGVL:4148

설명: DX_INF_MFC_HW_Check: 전역 변수는 'g' 접두사 사용 권장 (예: gSystemStatus)

⚠️ 위험성:

명명 규칙 위반은 다음 문제를 야기합니다: - 코드 가독성 저하 - 변수 용도 파악 어려움 - 팀 협업 시 혼란 - 유지보수 비용 증가 - 일관성 없는 코드베이스
💡 권장 해결 방법:
✅ 권장 명명 규칙:

1. Function Block
   FB_ConveyorControl  // FB_ 접두사

2. 전역 변수
   gSystemStatus       // g 접두사
   GVL.temperature     // GVL (Global Variable List)

3. 입력 변수
   iSensorValue        // i 접두사 (또는 in)

4. 출력 변수
   oMotorSpeed         // o 접두사 (또는 out)

5. 로컬 변수
   currentSpeed        // 소문자 카멜 케이스
   isRunning           // is/has 접두사 (BOOL)

6. 상수
   MAX_SPEED           // 대문자 스네이크 케이스
   PI_VALUE

7. 데이터 타입
   TYPE T_SensorData   // T_ 접두사
   TYPE E_ErrorCode    // E_ 접두사 (열거형)
   TYPE ST_Config      // ST_ 접두사 (구조체)

올바른 이름: gDX_INF_MFC_HW_Check

예시:

❌ 잘못된 예:
sensor : INT; // 범위 불명확
x : BOOL; // 의미 불명확
MyFB : ... // FB_ 접두사 없음

✅ 올바른 예:
VAR_GLOBAL
gSystemReady : BOOL; // 전역
END_VAR

VAR_INPUT
iTemperature : REAL; // 입력
END_VAR

FUNCTION_BLOCK FB_MotorControl // FB
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\MAIN.TcPOU:1

설명: MAIN: 코드에 의미 불명확한 숫자 사용 (3, 6)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 3, 6
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: FindValue_Inverse_TempParaTable: 코드에 의미 불명확한 숫자 사용 (3, 4, 5, 6, 03573)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 3, 4, 5, 6, 03573
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: FindValue_Inverse_TempParaTable: 63줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: FindValue_Inverse_TempParaTable = 63줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA009] 중첩 구조가 너무 깊음

카테고리: 코드 복잡도

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: FindValue_Inverse_TempParaTable: 최대 4단계 중첩 (권장: 3단계 이하)

⚠️ 위험성:

깊은 중첩 구조는 다음 문제를 야기합니다: - 코드 이해 및 추적 어려움 - 순환 복잡도(Cyclomatic Complexity) 증가 - 버그 발생 가능성 증가 - 테스트 케이스 작성 어려움 - 유지보수 비용 증가
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Early Return 패턴 사용
   ❌ IF condition1 THEN
          IF condition2 THEN
              IF condition3 THEN
                  // 작업
              END_IF
          END_IF
       END_IF

   ✅ IF NOT condition1 THEN RETURN; END_IF
      IF NOT condition2 THEN RETURN; END_IF
      IF NOT condition3 THEN RETURN; END_IF
      // 작업

2. 조건 결합
   ❌ IF a THEN
          IF b THEN
              // 작업
          END_IF
       END_IF

   ✅ IF a AND b THEN
          // 작업
       END_IF

3. 별도 함수로 추출
   IF ComplexCondition() THEN
       ProcessData();
   END_IF

   FUNCTION ComplexCondition : BOOL
       ComplexCondition := condition1 AND condition2;
   END_FUNCTION

4. 상태 머신으로 변환
   CASE state OF
       STATE_INIT: ...
       STATE_PROCESS: ...
       STATE_COMPLETE: ...
   END_CASE

예시:

현재 중첩 레벨: 4단계

리팩토링 예시:
// Early Return 사용
IF NOT sensorOK THEN
errorFlag := TRUE;
RETURN;
END_IF

IF NOT motorReady THEN
RETURN;
END_IF

// 정상 처리
ProcessData();
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: FindValue_TempParaTable: 코드에 의미 불명확한 숫자 사용 (3, 4, 5, 6, 03573)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 3, 4, 5, 6, 03573
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: FindValue_TempParaTable: 63줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: FindValue_TempParaTable = 63줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA009] 중첩 구조가 너무 깊음

카테고리: 코드 복잡도

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: FindValue_TempParaTable: 최대 4단계 중첩 (권장: 3단계 이하)

⚠️ 위험성:

깊은 중첩 구조는 다음 문제를 야기합니다: - 코드 이해 및 추적 어려움 - 순환 복잡도(Cyclomatic Complexity) 증가 - 버그 발생 가능성 증가 - 테스트 케이스 작성 어려움 - 유지보수 비용 증가
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Early Return 패턴 사용
   ❌ IF condition1 THEN
          IF condition2 THEN
              IF condition3 THEN
                  // 작업
              END_IF
          END_IF
       END_IF

   ✅ IF NOT condition1 THEN RETURN; END_IF
      IF NOT condition2 THEN RETURN; END_IF
      IF NOT condition3 THEN RETURN; END_IF
      // 작업

2. 조건 결합
   ❌ IF a THEN
          IF b THEN
              // 작업
          END_IF
       END_IF

   ✅ IF a AND b THEN
          // 작업
       END_IF

3. 별도 함수로 추출
   IF ComplexCondition() THEN
       ProcessData();
   END_IF

   FUNCTION ComplexCondition : BOOL
       ComplexCondition := condition1 AND condition2;
   END_FUNCTION

4. 상태 머신으로 변환
   CASE state OF
       STATE_INIT: ...
       STATE_PROCESS: ...
       STATE_COMPLETE: ...
   END_CASE

예시:

현재 중첩 레벨: 4단계

리팩토링 예시:
// Early Return 사용
IF NOT sensorOK THEN
errorFlag := TRUE;
RETURN;
END_IF

IF NOT motorReady THEN
RETURN;
END_IF

// 정상 처리
ProcessData();
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Add_EventLog_buffer.TcPOU:1

설명: F_Add_EventLog_buffer: 코드에 의미 불명확한 숫자 사용 (11)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 11
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_CheckMainZone.TcPOU:1

설명: F_CheckMainZone: 코드에 의미 불명확한 숫자 사용 (12, 3, 4, 5, 6, 7, 8, 9, 11)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 12, 3, 4, 5, 6, 7, 8, 9, 11
🟡 Warning [QA011] CASE 문에 ELSE 절 누락

카테고리: 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_CheckMainZone.TcPOU:10

설명: F_CheckMainZone: CASE 문에 기본 처리(ELSE) 없음

⚠️ 위험성:

CASE ELSE 누락은 다음 위험을 야기합니다: - 예상치 못한 값 처리 불가 - 시스템 상태 불명확 - 디버깅 어려움 (어느 분기도 실행 안됨) - 안전 관련 동작 누락 가능 - 런타임 오류 발생 가능
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. ELSE 절 추가 (에러 처리)
   CASE state OF
       0: // 초기 상태
       1: // 실행 상태
       2: // 완료 상태
   ELSE
       // 예상치 못한 값
       errorFlag := TRUE;
       errorCode := 9999;
       state := 0;  // 안전 상태로 복귀
   END_CASE

2. 모든 가능한 값 명시 (열거형 사용)
   TYPE E_State : (INIT, RUNNING, COMPLETE);
   END_TYPE

   CASE state OF
       E_State.INIT: ...
       E_State.RUNNING: ...
       E_State.COMPLETE: ...
   ELSE
       // 방어 코드
   END_CASE

3. 로그 기록
   ELSE
       LogError('알 수 없는 상태: %d', state);
       state := E_State.INIT;
   END_CASE

예시:

❌ 위험한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
END_CASE // mode=3이면?

✅ 안전한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
ELSE
errorFlag := TRUE;
EmergencyStop();
END_CASE
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_CheckMFCUse.TcPOU:1

설명: F_CheckMFCUse: 코드에 의미 불명확한 숫자 사용 (5, 34)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 5, 34
🟡 Warning [QA011] CASE 문에 ELSE 절 누락

카테고리: 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_CheckMFCUse.TcPOU:7

설명: F_CheckMFCUse: CASE 문에 기본 처리(ELSE) 없음

⚠️ 위험성:

CASE ELSE 누락은 다음 위험을 야기합니다: - 예상치 못한 값 처리 불가 - 시스템 상태 불명확 - 디버깅 어려움 (어느 분기도 실행 안됨) - 안전 관련 동작 누락 가능 - 런타임 오류 발생 가능
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. ELSE 절 추가 (에러 처리)
   CASE state OF
       0: // 초기 상태
       1: // 실행 상태
       2: // 완료 상태
   ELSE
       // 예상치 못한 값
       errorFlag := TRUE;
       errorCode := 9999;
       state := 0;  // 안전 상태로 복귀
   END_CASE

2. 모든 가능한 값 명시 (열거형 사용)
   TYPE E_State : (INIT, RUNNING, COMPLETE);
   END_TYPE

   CASE state OF
       E_State.INIT: ...
       E_State.RUNNING: ...
       E_State.COMPLETE: ...
   ELSE
       // 방어 코드
   END_CASE

3. 로그 기록
   ELSE
       LogError('알 수 없는 상태: %d', state);
       state := E_State.INIT;
   END_CASE

예시:

❌ 위험한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
END_CASE // mode=3이면?

✅ 안전한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
ELSE
errorFlag := TRUE;
EmergencyStop();
END_CASE
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: F_Cycle_StepCount: 89줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: F_Cycle_StepCount = 89줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: F_Cycle_StepCount_1: 89줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: F_Cycle_StepCount_1 = 89줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Boat_Elevator.TcPOU:1

설명: F_Driver_Boat_Elevator: 코드에 의미 불명확한 숫자 사용 (255, 01, 30, 02, 03)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 255, 01, 30, 02, 03
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Extract_Array.TcPOU:1

설명: F_Driver_Heater_Extract_Array: 코드에 의미 불명확한 숫자 사용 (8, 01197, 0.0)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 8, 01197, 0.0
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Read_Array.TcPOU:1

설명: F_Driver_Heater_Read_Array: 코드에 의미 불명확한 숫자 사용 (255, 02, 30, 31, 53, 8, 03)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 255, 02, 30, 31, 53, 8, 03
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Write_Array.TcPOU:1

설명: F_Driver_Heater_Write_Array: 코드에 의미 불명확한 숫자 사용 (255, 02, 30, 31, 53, 8, 03)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 255, 02, 30, 31, 53, 8, 03
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_EventLog_Shift.TcPOU:1

설명: F_EventLog_Shift: 코드에 의미 불명확한 숫자 사용 (3)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 3
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_FFU_CheckSum_Send.TcPOU:1

설명: F_FFU_CheckSum_Send: 코드에 의미 불명확한 숫자 사용 (8, 256, 16)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 8, 256, 16
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Function_LV_Log.TcPOU:1

설명: F_Function_LV_Log: 코드에 의미 불명확한 숫자 사용 (255)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 255
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Function_Process_Log.TcPOU:1

설명: F_Function_Process_Log: 코드에 의미 불명확한 숫자 사용 (255)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 255
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Func.TcPOU:1

설명: F_MarsLog_Func: 코드에 의미 불명확한 숫자 사용 (8, 3, 4, 5, 6, 7)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 8, 3, 4, 5, 6, 7
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Process.TcPOU:1

설명: F_MarsLog_Process: 코드에 의미 불명확한 숫자 사용 (14, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 14, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Process.TcPOU:1

설명: F_MarsLog_Process: 72줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: F_MarsLog_Process = 72줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_RealRound.TcPOU:1

설명: F_RealRound: 코드에 의미 불명확한 숫자 사용 (10.0, 0.51)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 10.0, 0.51
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_StepName_Search.TcPOU:1

설명: F_StepName_Search: 코드에 의미 불명확한 숫자 사용 (03551, 03550)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 03551, 03550
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Time_Conversion.TcPOU:1

설명: F_Time_Conversion: 코드에 의미 불명확한 숫자 사용 (4, 3600, 60)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 4, 3600, 60
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\Get_IEEE754.TcPOU:1

설명: Get_IEEE754: 코드에 의미 불명확한 숫자 사용 (3)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 3
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\Put_IEEE754.TcPOU:1

설명: Put_IEEE754: 코드에 의미 불명확한 숫자 사용 (8)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 8
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_ROUND.TcPOU:1

설명: REAL_ROUND: 코드에 의미 불명확한 숫자 사용 (10.0, 0.51)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 10.0, 0.51
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\REAL_TO_STR.TcPOU:1

설명: REAL_TO_STR: 코드에 의미 불명확한 숫자 사용 (128, 7, 2.30258509299405, 8)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 128, 7, 2.30258509299405, 8
🟡 Warning [QA009] 중첩 구조가 너무 깊음

카테고리: 코드 복잡도

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: FB_Alarm: 최대 5단계 중첩 (권장: 3단계 이하)

⚠️ 위험성:

깊은 중첩 구조는 다음 문제를 야기합니다: - 코드 이해 및 추적 어려움 - 순환 복잡도(Cyclomatic Complexity) 증가 - 버그 발생 가능성 증가 - 테스트 케이스 작성 어려움 - 유지보수 비용 증가
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Early Return 패턴 사용
   ❌ IF condition1 THEN
          IF condition2 THEN
              IF condition3 THEN
                  // 작업
              END_IF
          END_IF
       END_IF

   ✅ IF NOT condition1 THEN RETURN; END_IF
      IF NOT condition2 THEN RETURN; END_IF
      IF NOT condition3 THEN RETURN; END_IF
      // 작업

2. 조건 결합
   ❌ IF a THEN
          IF b THEN
              // 작업
          END_IF
       END_IF

   ✅ IF a AND b THEN
          // 작업
       END_IF

3. 별도 함수로 추출
   IF ComplexCondition() THEN
       ProcessData();
   END_IF

   FUNCTION ComplexCondition : BOOL
       ComplexCondition := condition1 AND condition2;
   END_FUNCTION

4. 상태 머신으로 변환
   CASE state OF
       STATE_INIT: ...
       STATE_PROCESS: ...
       STATE_COMPLETE: ...
   END_CASE

예시:

현재 중첩 레벨: 5단계

리팩토링 예시:
// Early Return 사용
IF NOT sensorOK THEN
errorFlag := TRUE;
RETURN;
END_IF

IF NOT motorReady THEN
RETURN;
END_IF

// 정상 처리
ProcessData();
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: FB_BasicPID_RSD: 코드에 의미 불명확한 숫자 사용 (0.0, 60)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 0.0, 60
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:1

설명: FB_Collection: 코드에 의미 불명확한 숫자 사용 (0.0)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 0.0
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:1

설명: FB_Collection: 56줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: FB_Collection = 56줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: FB_Control_Gas: 코드에 의미 불명확한 숫자 사용 (32767.0, 1.33, 20, 0.0, 4, 1000.0)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 32767.0, 1.33, 20, 0.0, 4, 1000.0
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:1

설명: FB_EXPLICT_MESSAGE: 코드에 의미 불명확한 숫자 사용 (16, 0033, 256, 19, 0034, 6, 1007)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 16, 0033, 256, 19, 0034, 6, 1007
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Heater_Group_Scan.TcPOU:1

설명: FB_Interlock_Heater_Group_Scan: 코드에 의미 불명확한 숫자 사용 (5)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 5
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:1

설명: FB_Interlock_Module: 코드에 의미 불명확한 숫자 사용 (200, 16)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 200, 16
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Module.TcPOU:1

설명: FB_Interlock_Module: 59줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: FB_Interlock_Module = 59줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: FB_Interlock_Valve: 80줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: FB_Interlock_Valve = 80줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:1

설명: FB_Sdo_Gas: 코드에 의미 불명확한 숫자 사용 (6, 2.5, 80, 16, 00, 255, 01, 02, 03, 08, 09)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 6, 2.5, 80, 16, 00, 255, 01, 02, 03, 08, 09
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas_PartsPara.TcPOU:1

설명: FB_Sdo_Gas_PartsPara: 코드에 의미 불명확한 숫자 사용 (128, 20, 16, 1008, 1009, 02, 03, 04, 07, 9000, 01, 9001, 5001)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 128, 20, 16, 1008, 1009, 02, 03, 04, 07, 9000, 01, 9001, 5001
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Signal_2BYTE.TcPOU:1

설명: FB_Signal_2BYTE: 코드에 의미 불명확한 숫자 사용 (15)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 15
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:1

설명: FB_Temp_DEV_And_Short: 72줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: FB_Temp_DEV_And_Short = 72줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:1

설명: FB_Temp_DEV_Zone_to_Zone: 55줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: FB_Temp_DEV_Zone_to_Zone = 55줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:1

설명: FB_Temp_DEV_Zone_to_Zone_Option: 62줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: FB_Temp_DEV_Zone_to_Zone_Option = 62줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Timer.TcPOU:1

설명: FB_Timer: 코드에 의미 불명확한 숫자 사용 (10000)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 10000
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: FB_VG_Cal: 코드에 의미 불명확한 숫자 사용 (5, 16, 01, 02, 03, 1018, 04, 3)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 5, 16, 01, 02, 03, 1018, 04, 3
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:1

설명: FB_Warn_Alarm_Rang_Signal: 코드에 의미 불명확한 숫자 사용 (100.0)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 100.0
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:1

설명: FB_Warn_Alarm_Rang_Signal: 58줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: FB_Warn_Alarm_Rang_Signal = 58줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver.TcPOU:1

설명: SEQ_Driver: 코드에 의미 불명확한 숫자 사용 (20, 50)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 20, 50
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:1

설명: SEQ_Driver_APC: 코드에 의미 불명확한 숫자 사용 (16, 5050, 11, 12, 13, 22, 8060, 30, 31, 32, 36, 37, 38, 39, 220, 190)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 16, 5050, 11, 12, 13, 22, 8060, 30, 31, 32, 36, 37, 38, 39, 220, 190
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: SEQ_Driver_FFU_EtherCAT: 코드에 의미 불명확한 숫자 사용 (3, 16011, 16051, 30, 16031, 16041, 6, 16061, 9)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 3, 16011, 16051, 30, 16031, 16041, 6, 16061, 9
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: SEQ_Driver_FFU_EtherCAT: 97줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Driver_FFU_EtherCAT = 97줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_NGK_O2Analyzer.TcPOU:1

설명: SEQ_Driver_NGK_O2Analyzer: 코드에 의미 불명확한 숫자 사용 (255, 9600, 206000.000, 20.6, 1000000.000, 100.00, 100.000, 0.000, 3, 4, 5, 6, 7)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 255, 9600, 206000.000, 20.6, 1000000.000, 100.00, 100.000, 0.000, 3, 4, 5, 6, 7
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: SEQ_Driver_O2Analyzer: 코드에 의미 불명확한 숫자 사용 (255, 9600, 206000.000, 20.6, 1000000.000, 100.00, 100.000, 0.000, 15211, 200, 3, 4)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 255, 9600, 206000.000, 20.6, 1000000.000, 100.00, 100.000, 0.000, 15211, 200, 3, 4
🟡 Warning [QA009] 중첩 구조가 너무 깊음

카테고리: 코드 복잡도

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: SEQ_Driver_O2Analyzer: 최대 4단계 중첩 (권장: 3단계 이하)

⚠️ 위험성:

깊은 중첩 구조는 다음 문제를 야기합니다: - 코드 이해 및 추적 어려움 - 순환 복잡도(Cyclomatic Complexity) 증가 - 버그 발생 가능성 증가 - 테스트 케이스 작성 어려움 - 유지보수 비용 증가
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Early Return 패턴 사용
   ❌ IF condition1 THEN
          IF condition2 THEN
              IF condition3 THEN
                  // 작업
              END_IF
          END_IF
       END_IF

   ✅ IF NOT condition1 THEN RETURN; END_IF
      IF NOT condition2 THEN RETURN; END_IF
      IF NOT condition3 THEN RETURN; END_IF
      // 작업

2. 조건 결합
   ❌ IF a THEN
          IF b THEN
              // 작업
          END_IF
       END_IF

   ✅ IF a AND b THEN
          // 작업
       END_IF

3. 별도 함수로 추출
   IF ComplexCondition() THEN
       ProcessData();
   END_IF

   FUNCTION ComplexCondition : BOOL
       ComplexCondition := condition1 AND condition2;
   END_FUNCTION

4. 상태 머신으로 변환
   CASE state OF
       STATE_INIT: ...
       STATE_PROCESS: ...
       STATE_COMPLETE: ...
   END_CASE

예시:

현재 중첩 레벨: 4단계

리팩토링 예시:
// Early Return 사용
IF NOT sensorOK THEN
errorFlag := TRUE;
RETURN;
END_IF

IF NOT motorReady THEN
RETURN;
END_IF

// 정상 처리
ProcessData();
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: SEQ_Driver_SdoMfc: 코드에 의미 불명확한 숫자 사용 (60, 80, 13961, 13962, 13001, 5, 3.5, 5.5, 10010, 20)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 60, 80, 13961, 13962, 13001, 5, 3.5, 5.5, 10010, 20
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:1

설명: SEQ_Driver_TCPIP: 코드에 의미 불명확한 숫자 사용 (255)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 255
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: SEQ_Driver_TVLPV: 코드에 의미 불명확한 숫자 사용 (48, 6, 25801, 25802, 25803, 3, 25804, 25805, 25641, 11, 25642, 12, 25643, 13, 25644, 25811, 25821, 25831, 25841, 4, 5, 7, 8, 9, 24, 25)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 48, 6, 25801, 25802, 25803, 3, 25804, 25805, 25641, 11, 25642, 12, 25643, 13, 25644, 25811, 25821, 25831, 25841, 4, 5, 7, 8, 9, 24, 25
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: SEQ_Driver_TV_VAT: 코드에 의미 불명확한 숫자 사용 (30, 50, 11, 12, 31, 51, 26311)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 30, 50, 11, 12, 31, 51, 26311
🟡 Warning [QA011] CASE 문에 ELSE 절 누락

카테고리: 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:32

설명: SEQ_Driver_TV_VAT: CASE 문에 기본 처리(ELSE) 없음

⚠️ 위험성:

CASE ELSE 누락은 다음 위험을 야기합니다: - 예상치 못한 값 처리 불가 - 시스템 상태 불명확 - 디버깅 어려움 (어느 분기도 실행 안됨) - 안전 관련 동작 누락 가능 - 런타임 오류 발생 가능
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. ELSE 절 추가 (에러 처리)
   CASE state OF
       0: // 초기 상태
       1: // 실행 상태
       2: // 완료 상태
   ELSE
       // 예상치 못한 값
       errorFlag := TRUE;
       errorCode := 9999;
       state := 0;  // 안전 상태로 복귀
   END_CASE

2. 모든 가능한 값 명시 (열거형 사용)
   TYPE E_State : (INIT, RUNNING, COMPLETE);
   END_TYPE

   CASE state OF
       E_State.INIT: ...
       E_State.RUNNING: ...
       E_State.COMPLETE: ...
   ELSE
       // 방어 코드
   END_CASE

3. 로그 기록
   ELSE
       LogError('알 수 없는 상태: %d', state);
       state := E_State.INIT;
   END_CASE

예시:

❌ 위험한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
END_CASE // mode=3이면?

✅ 안전한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
ELSE
errorFlag := TRUE;
EmergencyStop();
END_CASE
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VAC_O2Analyzer.TcPOU:1

설명: SEQ_Driver_VAC_O2Analyzer: 코드에 의미 불명확한 숫자 사용 (255, 9600, 32, 3, 15212, 4, 5, 41, 31, 6)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 255, 9600, 32, 3, 15212, 4, 5, 41, 31, 6
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: SEQ_Driver_VG: 코드에 의미 불명확한 숫자 사용 (26251, 24.10, 22, 26252, 26253, 26256, 26257, 26258, 26261, 26262, 26263, 26266, 26267, 26268, 26271, 26272, 26273, 26020, 26060, 3, 26100, 4, 26140)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 26251, 24.10, 22, 26252, 26253, 26256, 26257, 26258, 26261, 26262, 26263, 26266, 26267, 26268, 26271, 26272, 26273, 26020, 26060, 3, 26100, 4, 26140
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: SEQ_Function_Auto_PID: 코드에 의미 불명확한 숫자 사용 (80, 5, 3600000, 04801, 3, 4, 6)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 80, 5, 3600000, 04801, 3, 4, 6
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: SEQ_Function_Auto_Profile: 코드에 의미 불명확한 숫자 사용 (80)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 80
🟡 Warning [QA011] CASE 문에 ELSE 절 누락

카테고리: 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:64

설명: SEQ_Function_Auto_Profile: CASE 문에 기본 처리(ELSE) 없음

⚠️ 위험성:

CASE ELSE 누락은 다음 위험을 야기합니다: - 예상치 못한 값 처리 불가 - 시스템 상태 불명확 - 디버깅 어려움 (어느 분기도 실행 안됨) - 안전 관련 동작 누락 가능 - 런타임 오류 발생 가능
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. ELSE 절 추가 (에러 처리)
   CASE state OF
       0: // 초기 상태
       1: // 실행 상태
       2: // 완료 상태
   ELSE
       // 예상치 못한 값
       errorFlag := TRUE;
       errorCode := 9999;
       state := 0;  // 안전 상태로 복귀
   END_CASE

2. 모든 가능한 값 명시 (열거형 사용)
   TYPE E_State : (INIT, RUNNING, COMPLETE);
   END_TYPE

   CASE state OF
       E_State.INIT: ...
       E_State.RUNNING: ...
       E_State.COMPLETE: ...
   ELSE
       // 방어 코드
   END_CASE

3. 로그 기록
   ELSE
       LogError('알 수 없는 상태: %d', state);
       state := E_State.INIT;
   END_CASE

예시:

❌ 위험한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
END_CASE // mode=3이면?

✅ 안전한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
ELSE
errorFlag := TRUE;
EmergencyStop();
END_CASE
🟡 Warning [QA011] CASE 문에 ELSE 절 누락

카테고리: 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:84

설명: SEQ_Function_Auto_Profile: CASE 문에 기본 처리(ELSE) 없음

⚠️ 위험성:

CASE ELSE 누락은 다음 위험을 야기합니다: - 예상치 못한 값 처리 불가 - 시스템 상태 불명확 - 디버깅 어려움 (어느 분기도 실행 안됨) - 안전 관련 동작 누락 가능 - 런타임 오류 발생 가능
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. ELSE 절 추가 (에러 처리)
   CASE state OF
       0: // 초기 상태
       1: // 실행 상태
       2: // 완료 상태
   ELSE
       // 예상치 못한 값
       errorFlag := TRUE;
       errorCode := 9999;
       state := 0;  // 안전 상태로 복귀
   END_CASE

2. 모든 가능한 값 명시 (열거형 사용)
   TYPE E_State : (INIT, RUNNING, COMPLETE);
   END_TYPE

   CASE state OF
       E_State.INIT: ...
       E_State.RUNNING: ...
       E_State.COMPLETE: ...
   ELSE
       // 방어 코드
   END_CASE

3. 로그 기록
   ELSE
       LogError('알 수 없는 상태: %d', state);
       state := E_State.INIT;
   END_CASE

예시:

❌ 위험한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
END_CASE // mode=3이면?

✅ 안전한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
ELSE
errorFlag := TRUE;
EmergencyStop();
END_CASE
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: SEQ_Function_Auto_RDNP: 코드에 의미 불명확한 숫자 사용 (80, 5, 3600000, 3, 4)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 80, 5, 3600000, 3, 4
🟡 Warning [QA009] 중첩 구조가 너무 깊음

카테고리: 코드 복잡도

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: SEQ_Function_Auto_RDNP: 최대 7단계 중첩 (권장: 3단계 이하)

⚠️ 위험성:

깊은 중첩 구조는 다음 문제를 야기합니다: - 코드 이해 및 추적 어려움 - 순환 복잡도(Cyclomatic Complexity) 증가 - 버그 발생 가능성 증가 - 테스트 케이스 작성 어려움 - 유지보수 비용 증가
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Early Return 패턴 사용
   ❌ IF condition1 THEN
          IF condition2 THEN
              IF condition3 THEN
                  // 작업
              END_IF
          END_IF
       END_IF

   ✅ IF NOT condition1 THEN RETURN; END_IF
      IF NOT condition2 THEN RETURN; END_IF
      IF NOT condition3 THEN RETURN; END_IF
      // 작업

2. 조건 결합
   ❌ IF a THEN
          IF b THEN
              // 작업
          END_IF
       END_IF

   ✅ IF a AND b THEN
          // 작업
       END_IF

3. 별도 함수로 추출
   IF ComplexCondition() THEN
       ProcessData();
   END_IF

   FUNCTION ComplexCondition : BOOL
       ComplexCondition := condition1 AND condition2;
   END_FUNCTION

4. 상태 머신으로 변환
   CASE state OF
       STATE_INIT: ...
       STATE_PROCESS: ...
       STATE_COMPLETE: ...
   END_CASE

예시:

현재 중첩 레벨: 7단계

리팩토링 예시:
// Early Return 사용
IF NOT sensorOK THEN
errorFlag := TRUE;
RETURN;
END_IF

IF NOT motorReady THEN
RETURN;
END_IF

// 정상 처리
ProcessData();
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: SEQ_Function_PartsPara: 코드에 의미 불명확한 숫자 사용 (80, 3, 36, 4, 5, 6, 1.2)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 80, 3, 36, 4, 5, 6, 1.2
🟡 Warning [QA009] 중첩 구조가 너무 깊음

카테고리: 코드 복잡도

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: SEQ_Function_PartsPara: 최대 5단계 중첩 (권장: 3단계 이하)

⚠️ 위험성:

깊은 중첩 구조는 다음 문제를 야기합니다: - 코드 이해 및 추적 어려움 - 순환 복잡도(Cyclomatic Complexity) 증가 - 버그 발생 가능성 증가 - 테스트 케이스 작성 어려움 - 유지보수 비용 증가
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Early Return 패턴 사용
   ❌ IF condition1 THEN
          IF condition2 THEN
              IF condition3 THEN
                  // 작업
              END_IF
          END_IF
       END_IF

   ✅ IF NOT condition1 THEN RETURN; END_IF
      IF NOT condition2 THEN RETURN; END_IF
      IF NOT condition3 THEN RETURN; END_IF
      // 작업

2. 조건 결합
   ❌ IF a THEN
          IF b THEN
              // 작업
          END_IF
       END_IF

   ✅ IF a AND b THEN
          // 작업
       END_IF

3. 별도 함수로 추출
   IF ComplexCondition() THEN
       ProcessData();
   END_IF

   FUNCTION ComplexCondition : BOOL
       ComplexCondition := condition1 AND condition2;
   END_FUNCTION

4. 상태 머신으로 변환
   CASE state OF
       STATE_INIT: ...
       STATE_PROCESS: ...
       STATE_COMPLETE: ...
   END_CASE

예시:

현재 중첩 레벨: 5단계

리팩토링 예시:
// Early Return 사용
IF NOT sensorOK THEN
errorFlag := TRUE;
RETURN;
END_IF

IF NOT motorReady THEN
RETURN;
END_IF

// 정상 처리
ProcessData();
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:1

설명: SEQ_Function_Process: 코드에 의미 불명확한 숫자 사용 (80)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 80
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: SEQ_Interface: 코드에 의미 불명확한 숫자 사용 (80, 03001, 03041)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 80, 03001, 03041
🟡 Warning [QA011] CASE 문에 ELSE 절 누락

카테고리: 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:72

설명: SEQ_Interface: CASE 문에 기본 처리(ELSE) 없음

⚠️ 위험성:

CASE ELSE 누락은 다음 위험을 야기합니다: - 예상치 못한 값 처리 불가 - 시스템 상태 불명확 - 디버깅 어려움 (어느 분기도 실행 안됨) - 안전 관련 동작 누락 가능 - 런타임 오류 발생 가능
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. ELSE 절 추가 (에러 처리)
   CASE state OF
       0: // 초기 상태
       1: // 실행 상태
       2: // 완료 상태
   ELSE
       // 예상치 못한 값
       errorFlag := TRUE;
       errorCode := 9999;
       state := 0;  // 안전 상태로 복귀
   END_CASE

2. 모든 가능한 값 명시 (열거형 사용)
   TYPE E_State : (INIT, RUNNING, COMPLETE);
   END_TYPE

   CASE state OF
       E_State.INIT: ...
       E_State.RUNNING: ...
       E_State.COMPLETE: ...
   ELSE
       // 방어 코드
   END_CASE

3. 로그 기록
   ELSE
       LogError('알 수 없는 상태: %d', state);
       state := E_State.INIT;
   END_CASE

예시:

❌ 위험한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
END_CASE // mode=3이면?

✅ 안전한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
ELSE
errorFlag := TRUE;
EmergencyStop();
END_CASE
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Safety.TcPOU:1

설명: SEQ_Interlock_Safety: 코드에 의미 불명확한 숫자 사용 (400, 200, 5)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 400, 200, 5
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: SEQ_Interlock_Valve: 코드에 의미 불명확한 숫자 사용 (3, 5, 9, 6, 12, 26, 13)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 3, 5, 9, 6, 12, 26, 13
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: SEQ_Physical_APC: 코드에 의미 불명확한 숫자 사용 (255, 80, 0.0)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 255, 80, 0.0
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: SEQ_Physical_Boat_Elevator: 코드에 의미 불명확한 숫자 사용 (80, 20140730, 14041, 2002)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 80, 20140730, 14041, 2002
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: SEQ_Physical_Boat_Rotation: 코드에 의미 불명확한 숫자 사용 (80, 14621, 14623, 14624, 7, 3, 14625, 4, 5, 6, 14626)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 80, 14621, 14623, 14624, 7, 3, 14625, 4, 5, 6, 14626
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: SEQ_Physical_FRPTV: 코드에 의미 불명확한 숫자 사용 (80, 60, 8000, 16455, 3, 4, 16463, 16464, 5, 6)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 80, 60, 8000, 16455, 3, 4, 16463, 16464, 5, 6
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: SEQ_Physical_Heater_Shutter: 코드에 의미 불명확한 숫자 사용 (80, 7, 15002, 3, 4, 2321, 15004, 15005)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 80, 7, 15002, 3, 4, 2321, 15004, 15005
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: SEQ_Physical_LoadLock: 코드에 의미 불명확한 숫자 사용 (80, 15411, 15412, 3, 4)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 80, 15411, 15412, 3, 4
🟡 Warning [QA009] 중첩 구조가 너무 깊음

카테고리: 코드 복잡도

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: SEQ_Physical_LoadLock: 최대 4단계 중첩 (권장: 3단계 이하)

⚠️ 위험성:

깊은 중첩 구조는 다음 문제를 야기합니다: - 코드 이해 및 추적 어려움 - 순환 복잡도(Cyclomatic Complexity) 증가 - 버그 발생 가능성 증가 - 테스트 케이스 작성 어려움 - 유지보수 비용 증가
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Early Return 패턴 사용
   ❌ IF condition1 THEN
          IF condition2 THEN
              IF condition3 THEN
                  // 작업
              END_IF
          END_IF
       END_IF

   ✅ IF NOT condition1 THEN RETURN; END_IF
      IF NOT condition2 THEN RETURN; END_IF
      IF NOT condition3 THEN RETURN; END_IF
      // 작업

2. 조건 결합
   ❌ IF a THEN
          IF b THEN
              // 작업
          END_IF
       END_IF

   ✅ IF a AND b THEN
          // 작업
       END_IF

3. 별도 함수로 추출
   IF ComplexCondition() THEN
       ProcessData();
   END_IF

   FUNCTION ComplexCondition : BOOL
       ComplexCondition := condition1 AND condition2;
   END_FUNCTION

4. 상태 머신으로 변환
   CASE state OF
       STATE_INIT: ...
       STATE_PROCESS: ...
       STATE_COMPLETE: ...
   END_CASE

예시:

현재 중첩 레벨: 4단계

리팩토링 예시:
// Early Return 사용
IF NOT sensorOK THEN
errorFlag := TRUE;
RETURN;
END_IF

IF NOT motorReady THEN
RETURN;
END_IF

// 정상 처리
ProcessData();
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: SEQ_Physical_LPV: 코드에 의미 불명확한 숫자 사용 (80, 25611, 3, 4, 25624, 25625, 25612)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 80, 25611, 3, 4, 25624, 25625, 25612
🟡 Warning [QA009] 중첩 구조가 너무 깊음

카테고리: 코드 복잡도

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: SEQ_Physical_LPV: 최대 4단계 중첩 (권장: 3단계 이하)

⚠️ 위험성:

깊은 중첩 구조는 다음 문제를 야기합니다: - 코드 이해 및 추적 어려움 - 순환 복잡도(Cyclomatic Complexity) 증가 - 버그 발생 가능성 증가 - 테스트 케이스 작성 어려움 - 유지보수 비용 증가
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Early Return 패턴 사용
   ❌ IF condition1 THEN
          IF condition2 THEN
              IF condition3 THEN
                  // 작업
              END_IF
          END_IF
       END_IF

   ✅ IF NOT condition1 THEN RETURN; END_IF
      IF NOT condition2 THEN RETURN; END_IF
      IF NOT condition3 THEN RETURN; END_IF
      // 작업

2. 조건 결합
   ❌ IF a THEN
          IF b THEN
              // 작업
          END_IF
       END_IF

   ✅ IF a AND b THEN
          // 작업
       END_IF

3. 별도 함수로 추출
   IF ComplexCondition() THEN
       ProcessData();
   END_IF

   FUNCTION ComplexCondition : BOOL
       ComplexCondition := condition1 AND condition2;
   END_FUNCTION

4. 상태 머신으로 변환
   CASE state OF
       STATE_INIT: ...
       STATE_PROCESS: ...
       STATE_COMPLETE: ...
   END_CASE

예시:

현재 중첩 레벨: 4단계

리팩토링 예시:
// Early Return 사용
IF NOT sensorOK THEN
errorFlag := TRUE;
RETURN;
END_IF

IF NOT motorReady THEN
RETURN;
END_IF

// 정상 처리
ProcessData();
🟡 Warning [QA011] CASE 문에 ELSE 절 누락

카테고리: 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:39

설명: SEQ_Physical_LPV: CASE 문에 기본 처리(ELSE) 없음

⚠️ 위험성:

CASE ELSE 누락은 다음 위험을 야기합니다: - 예상치 못한 값 처리 불가 - 시스템 상태 불명확 - 디버깅 어려움 (어느 분기도 실행 안됨) - 안전 관련 동작 누락 가능 - 런타임 오류 발생 가능
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. ELSE 절 추가 (에러 처리)
   CASE state OF
       0: // 초기 상태
       1: // 실행 상태
       2: // 완료 상태
   ELSE
       // 예상치 못한 값
       errorFlag := TRUE;
       errorCode := 9999;
       state := 0;  // 안전 상태로 복귀
   END_CASE

2. 모든 가능한 값 명시 (열거형 사용)
   TYPE E_State : (INIT, RUNNING, COMPLETE);
   END_TYPE

   CASE state OF
       E_State.INIT: ...
       E_State.RUNNING: ...
       E_State.COMPLETE: ...
   ELSE
       // 방어 코드
   END_CASE

3. 로그 기록
   ELSE
       LogError('알 수 없는 상태: %d', state);
       state := E_State.INIT;
   END_CASE

예시:

❌ 위험한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
END_CASE // mode=3이면?

✅ 안전한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
ELSE
errorFlag := TRUE;
EmergencyStop();
END_CASE
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: SEQ_Physical_RSD: 코드에 의미 불명확한 숫자 사용 (47, 12, 13, 14, 15)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 47, 12, 13, 14, 15
🟡 Warning [QA009] 중첩 구조가 너무 깊음

카테고리: 코드 복잡도

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: SEQ_Physical_RSD: 최대 4단계 중첩 (권장: 3단계 이하)

⚠️ 위험성:

깊은 중첩 구조는 다음 문제를 야기합니다: - 코드 이해 및 추적 어려움 - 순환 복잡도(Cyclomatic Complexity) 증가 - 버그 발생 가능성 증가 - 테스트 케이스 작성 어려움 - 유지보수 비용 증가
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Early Return 패턴 사용
   ❌ IF condition1 THEN
          IF condition2 THEN
              IF condition3 THEN
                  // 작업
              END_IF
          END_IF
       END_IF

   ✅ IF NOT condition1 THEN RETURN; END_IF
      IF NOT condition2 THEN RETURN; END_IF
      IF NOT condition3 THEN RETURN; END_IF
      // 작업

2. 조건 결합
   ❌ IF a THEN
          IF b THEN
              // 작업
          END_IF
       END_IF

   ✅ IF a AND b THEN
          // 작업
       END_IF

3. 별도 함수로 추출
   IF ComplexCondition() THEN
       ProcessData();
   END_IF

   FUNCTION ComplexCondition : BOOL
       ComplexCondition := condition1 AND condition2;
   END_FUNCTION

4. 상태 머신으로 변환
   CASE state OF
       STATE_INIT: ...
       STATE_PROCESS: ...
       STATE_COMPLETE: ...
   END_CASE

예시:

현재 중첩 레벨: 4단계

리팩토링 예시:
// Early Return 사용
IF NOT sensorOK THEN
errorFlag := TRUE;
RETURN;
END_IF

IF NOT motorReady THEN
RETURN;
END_IF

// 정상 처리
ProcessData();
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: SEQ_Physical_TV_VAT: 코드에 의미 불명확한 숫자 사용 (255, 80, 3, 4, 26312, 26313)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 255, 80, 3, 4, 26312, 26313
🟡 Warning [QA011] CASE 문에 ELSE 절 누락

카테고리: 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:63

설명: SEQ_Physical_TV_VAT: CASE 문에 기본 처리(ELSE) 없음

⚠️ 위험성:

CASE ELSE 누락은 다음 위험을 야기합니다: - 예상치 못한 값 처리 불가 - 시스템 상태 불명확 - 디버깅 어려움 (어느 분기도 실행 안됨) - 안전 관련 동작 누락 가능 - 런타임 오류 발생 가능
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. ELSE 절 추가 (에러 처리)
   CASE state OF
       0: // 초기 상태
       1: // 실행 상태
       2: // 완료 상태
   ELSE
       // 예상치 못한 값
       errorFlag := TRUE;
       errorCode := 9999;
       state := 0;  // 안전 상태로 복귀
   END_CASE

2. 모든 가능한 값 명시 (열거형 사용)
   TYPE E_State : (INIT, RUNNING, COMPLETE);
   END_TYPE

   CASE state OF
       E_State.INIT: ...
       E_State.RUNNING: ...
       E_State.COMPLETE: ...
   ELSE
       // 방어 코드
   END_CASE

3. 로그 기록
   ELSE
       LogError('알 수 없는 상태: %d', state);
       state := E_State.INIT;
   END_CASE

예시:

❌ 위험한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
END_CASE // mode=3이면?

✅ 안전한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
ELSE
errorFlag := TRUE;
EmergencyStop();
END_CASE
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: SEQ_Physical_VG01: 코드에 의미 불명확한 숫자 사용 (5, 26001, 26011, 26012, 3, 4, 26021, 26022, 26023, 26024, 26025, 26026, 26027, 26028, 26029, 26030)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 5, 26001, 26011, 26012, 3, 4, 26021, 26022, 26023, 26024, 26025, 26026, 26027, 26028, 26029, 26030
🟡 Warning [QA011] CASE 문에 ELSE 절 누락

카테고리: 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:40

설명: SEQ_Physical_VG01: CASE 문에 기본 처리(ELSE) 없음

⚠️ 위험성:

CASE ELSE 누락은 다음 위험을 야기합니다: - 예상치 못한 값 처리 불가 - 시스템 상태 불명확 - 디버깅 어려움 (어느 분기도 실행 안됨) - 안전 관련 동작 누락 가능 - 런타임 오류 발생 가능
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. ELSE 절 추가 (에러 처리)
   CASE state OF
       0: // 초기 상태
       1: // 실행 상태
       2: // 완료 상태
   ELSE
       // 예상치 못한 값
       errorFlag := TRUE;
       errorCode := 9999;
       state := 0;  // 안전 상태로 복귀
   END_CASE

2. 모든 가능한 값 명시 (열거형 사용)
   TYPE E_State : (INIT, RUNNING, COMPLETE);
   END_TYPE

   CASE state OF
       E_State.INIT: ...
       E_State.RUNNING: ...
       E_State.COMPLETE: ...
   ELSE
       // 방어 코드
   END_CASE

3. 로그 기록
   ELSE
       LogError('알 수 없는 상태: %d', state);
       state := E_State.INIT;
   END_CASE

예시:

❌ 위험한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
END_CASE // mode=3이면?

✅ 안전한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
ELSE
errorFlag := TRUE;
EmergencyStop();
END_CASE
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: SEQ_Physical_VG02: 코드에 의미 불명확한 숫자 사용 (5, 26041, 26051, 26052, 3, 4, 26061, 26062, 26063, 26064, 26065, 26066, 26067, 26068, 26069, 26070)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 5, 26041, 26051, 26052, 3, 4, 26061, 26062, 26063, 26064, 26065, 26066, 26067, 26068, 26069, 26070
🟡 Warning [QA011] CASE 문에 ELSE 절 누락

카테고리: 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:40

설명: SEQ_Physical_VG02: CASE 문에 기본 처리(ELSE) 없음

⚠️ 위험성:

CASE ELSE 누락은 다음 위험을 야기합니다: - 예상치 못한 값 처리 불가 - 시스템 상태 불명확 - 디버깅 어려움 (어느 분기도 실행 안됨) - 안전 관련 동작 누락 가능 - 런타임 오류 발생 가능
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. ELSE 절 추가 (에러 처리)
   CASE state OF
       0: // 초기 상태
       1: // 실행 상태
       2: // 완료 상태
   ELSE
       // 예상치 못한 값
       errorFlag := TRUE;
       errorCode := 9999;
       state := 0;  // 안전 상태로 복귀
   END_CASE

2. 모든 가능한 값 명시 (열거형 사용)
   TYPE E_State : (INIT, RUNNING, COMPLETE);
   END_TYPE

   CASE state OF
       E_State.INIT: ...
       E_State.RUNNING: ...
       E_State.COMPLETE: ...
   ELSE
       // 방어 코드
   END_CASE

3. 로그 기록
   ELSE
       LogError('알 수 없는 상태: %d', state);
       state := E_State.INIT;
   END_CASE

예시:

❌ 위험한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
END_CASE // mode=3이면?

✅ 안전한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
ELSE
errorFlag := TRUE;
EmergencyStop();
END_CASE
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: SEQ_Physical_VG03: 코드에 의미 불명확한 숫자 사용 (5, 26081, 26091, 26101, 26102, 26103, 26104, 26105, 26106, 26107, 26108, 26109, 26110)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 5, 26081, 26091, 26101, 26102, 26103, 26104, 26105, 26106, 26107, 26108, 26109, 26110
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: SEQ_Physical_VG03: 95줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Physical_VG03 = 95줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA011] CASE 문에 ELSE 절 누락

카테고리: 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:40

설명: SEQ_Physical_VG03: CASE 문에 기본 처리(ELSE) 없음

⚠️ 위험성:

CASE ELSE 누락은 다음 위험을 야기합니다: - 예상치 못한 값 처리 불가 - 시스템 상태 불명확 - 디버깅 어려움 (어느 분기도 실행 안됨) - 안전 관련 동작 누락 가능 - 런타임 오류 발생 가능
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. ELSE 절 추가 (에러 처리)
   CASE state OF
       0: // 초기 상태
       1: // 실행 상태
       2: // 완료 상태
   ELSE
       // 예상치 못한 값
       errorFlag := TRUE;
       errorCode := 9999;
       state := 0;  // 안전 상태로 복귀
   END_CASE

2. 모든 가능한 값 명시 (열거형 사용)
   TYPE E_State : (INIT, RUNNING, COMPLETE);
   END_TYPE

   CASE state OF
       E_State.INIT: ...
       E_State.RUNNING: ...
       E_State.COMPLETE: ...
   ELSE
       // 방어 코드
   END_CASE

3. 로그 기록
   ELSE
       LogError('알 수 없는 상태: %d', state);
       state := E_State.INIT;
   END_CASE

예시:

❌ 위험한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
END_CASE // mode=3이면?

✅ 안전한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
ELSE
errorFlag := TRUE;
EmergencyStop();
END_CASE
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: SEQ_Physical_VG04: 코드에 의미 불명확한 숫자 사용 (5, 26121, 26131, 26141, 26142, 26143, 26144, 26145, 26146, 26147, 26148, 26149, 26150)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 5, 26121, 26131, 26141, 26142, 26143, 26144, 26145, 26146, 26147, 26148, 26149, 26150
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: SEQ_Physical_VG04: 95줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Physical_VG04 = 95줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA011] CASE 문에 ELSE 절 누락

카테고리: 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:40

설명: SEQ_Physical_VG04: CASE 문에 기본 처리(ELSE) 없음

⚠️ 위험성:

CASE ELSE 누락은 다음 위험을 야기합니다: - 예상치 못한 값 처리 불가 - 시스템 상태 불명확 - 디버깅 어려움 (어느 분기도 실행 안됨) - 안전 관련 동작 누락 가능 - 런타임 오류 발생 가능
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. ELSE 절 추가 (에러 처리)
   CASE state OF
       0: // 초기 상태
       1: // 실행 상태
       2: // 완료 상태
   ELSE
       // 예상치 못한 값
       errorFlag := TRUE;
       errorCode := 9999;
       state := 0;  // 안전 상태로 복귀
   END_CASE

2. 모든 가능한 값 명시 (열거형 사용)
   TYPE E_State : (INIT, RUNNING, COMPLETE);
   END_TYPE

   CASE state OF
       E_State.INIT: ...
       E_State.RUNNING: ...
       E_State.COMPLETE: ...
   ELSE
       // 방어 코드
   END_CASE

3. 로그 기록
   ELSE
       LogError('알 수 없는 상태: %d', state);
       state := E_State.INIT;
   END_CASE

예시:

❌ 위험한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
END_CASE // mode=3이면?

✅ 안전한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
ELSE
errorFlag := TRUE;
EmergencyStop();
END_CASE
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: SEQ_Physical_VG05: 코드에 의미 불명확한 숫자 사용 (5, 26161, 26171, 26181, 26182, 26183, 26184, 26185, 26186, 26187, 26188, 26189, 26190)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 5, 26161, 26171, 26181, 26182, 26183, 26184, 26185, 26186, 26187, 26188, 26189, 26190
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: SEQ_Physical_VG05: 95줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Physical_VG05 = 95줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA011] CASE 문에 ELSE 절 누락

카테고리: 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:40

설명: SEQ_Physical_VG05: CASE 문에 기본 처리(ELSE) 없음

⚠️ 위험성:

CASE ELSE 누락은 다음 위험을 야기합니다: - 예상치 못한 값 처리 불가 - 시스템 상태 불명확 - 디버깅 어려움 (어느 분기도 실행 안됨) - 안전 관련 동작 누락 가능 - 런타임 오류 발생 가능
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. ELSE 절 추가 (에러 처리)
   CASE state OF
       0: // 초기 상태
       1: // 실행 상태
       2: // 완료 상태
   ELSE
       // 예상치 못한 값
       errorFlag := TRUE;
       errorCode := 9999;
       state := 0;  // 안전 상태로 복귀
   END_CASE

2. 모든 가능한 값 명시 (열거형 사용)
   TYPE E_State : (INIT, RUNNING, COMPLETE);
   END_TYPE

   CASE state OF
       E_State.INIT: ...
       E_State.RUNNING: ...
       E_State.COMPLETE: ...
   ELSE
       // 방어 코드
   END_CASE

3. 로그 기록
   ELSE
       LogError('알 수 없는 상태: %d', state);
       state := E_State.INIT;
   END_CASE

예시:

❌ 위험한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
END_CASE // mode=3이면?

✅ 안전한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
ELSE
errorFlag := TRUE;
EmergencyStop();
END_CASE
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: SYS_DataExchange: 코드에 의미 불명확한 숫자 사용 (3)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 3
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: SYS_MFC_Self_Diagnosis: 코드에 의미 불명확한 숫자 사용 (10018, 20, 6, 16, 07, 3, 4, 5, 7)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 10018, 20, 6, 16, 07, 3, 4, 5, 7
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: SYS_Output: 코드에 의미 불명확한 숫자 사용 (6, 7, 3, 4, 5)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 6, 7, 3, 4, 5
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: SYS_Output: 84줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SYS_Output = 84줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendData.TcPOU:1

설명: SYS_TrendData: 코드에 의미 불명확한 숫자 사용 (91, 92, 93, 94, 95, 96, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 191, 192, 193, 194, 211, 212, 213, 214, 215, 216, 218, 221, 222, 223, 224, 227, 228, 230, 241, 242, 243, 244, 254, 255, 257, 258, 259, 270, 271, 272, 275, 276, 279, 280, 281, 282, 286, 287, 289, 290)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 91, 92, 93, 94, 95, 96, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 191, 192, 193, 194, 211, 212, 213, 214, 215, 216, 218, 221, 222, 223, 224, 227, 228, 230, 241, 242, 243, 244, 254, 255, 257, 258, 259, 270, 271, 272, 275, 276, 279, 280, 281, 282, 286, 287, 289, 290
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: SYS_TrendLog: 코드에 의미 불명확한 숫자 사용 (255, 11, 3, 4, 000, 5)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 255, 11, 3, 4, 000, 5
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:1

설명: FB_Temp_Control: 코드에 의미 불명확한 숫자 사용 (0.0)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 0.0
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:1

설명: FB_Temp_Control: 98줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: FB_Temp_Control = 98줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:1

설명: FB_Temp_Simulator: 코드에 의미 불명확한 숫자 사용 (0.1)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 0.1
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: SEQ_Driver_Mini8_ModBusTCP: 코드에 의미 불명확한 숫자 사용 (941, 20000, 2000)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 941, 20000, 2000
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: SEQ_Driver_X20: 코드에 의미 불명확한 숫자 사용 (3, 4, 5, 6)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 3, 4, 5, 6
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20.TcPOU:1

설명: SEQ_Driver_X20: 59줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: SEQ_Driver_X20 = 59줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_X20_ModBusTCP.TcPOU:1

설명: SEQ_Driver_X20_ModBusTCP: 코드에 의미 불명확한 숫자 사용 (72, 3, 200, 300, 8192, 8448, 8704, 255, 20, 32769)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 72, 3, 200, 300, 8192, 8448, 8704, 255, 20, 32769
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Function\F_TrendData_RealToString.TcPOU:1

설명: F_TrendData_RealToString: 코드에 의미 불명확한 숫자 사용 (11, 3, 4, 5)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 11, 3, 4, 5
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Function\F_TrendData_RealToString.TcPOU:1

설명: F_TrendData_RealToString: 58줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: F_TrendData_RealToString = 58줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_Alarm_Read: 코드에 의미 불명확한 숫자 사용 (32, 23001, 8, 3, 4, 5, 6, 7, 16, 64, 23, 4097, 1052, 5.20, 0.198, 4.1, 15, 3601)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 32, 23001, 8, 3, 4, 5, 6, 7, 16, 64, 23, 4097, 1052, 5.20, 0.198, 4.1, 15, 3601
🟡 Warning [QA008] 함수가 너무 김

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\HW_Alarm_Read.TcPOU:1

설명: HW_Alarm_Read: 93줄 (권장: 50줄 이하)

⚠️ 위험성:

긴 함수는 다음 문제를 야기합니다: - 코드 이해 어려움 (한눈에 파악 불가) - 재사용성 저하 - 테스트 어려움 (많은 시나리오) - 버그 발생 가능성 증가 - 유지보수 비용 증가 - PLC 사이클 타임 증가 위험
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 기능별로 Function Block 분리
   FUNCTION_BLOCK FB_MainLogic
       VAR
           sensor : FB_SensorProcessing;  // 센서 처리 분리
           motor : FB_MotorControl;       // 모터 제어 분리
       END_VAR

       sensor();  // 센서 처리
       motor();   // 모터 제어
   END_FUNCTION_BLOCK

2. 반복 코드는 별도 함수로 추출
   FUNCTION F_CalculateAverage : REAL
       VAR_INPUT
           values : ARRAY[1..10] OF REAL;
       END_VAR
       // 평균 계산 로직
   END_FUNCTION

3. 상태 머신 사용 (순차 로직)
   CASE step OF
       0: InitializeSystem();
       1: ProcessData();
       2: CheckResults();
   END_CASE

4. 각 블록은 50줄 이하로 유지
   - 단일 책임 원칙 준수
   - 함수명으로 의도 명확화

예시:

❌ 현재: HW_Alarm_Read = 93줄

✅ 리팩토링 예:
FUNCTION_BLOCK FB_Main
// 초기화 (10줄)
InitializeSystem();

// 센서 읽기 (15줄)
ReadSensors();

// 제어 로직 (20줄)
ControlLogic();
END_FUNCTION_BLOCK
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: LOG_Dcoll: 코드에 의미 불명확한 숫자 사용 (255, 84, 8, 03578, 3, 4, 5, 6, 7, 21, 20)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 255, 84, 8, 03578, 3, 4, 5, 6, 7, 21, 20
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: LOG_Event: 코드에 의미 불명확한 숫자 사용 (255, 50, 3, 4, 5)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 255, 50, 3, 4, 5
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: LOG_Mars: 코드에 의미 불명확한 숫자 사용 (3, 4, 255, 8)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 3, 4, 255, 8
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: LOG_Parameter: 코드에 의미 불명확한 숫자 사용 (255, 6, 3, 4, 5, 7, 50)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 255, 6, 3, 4, 5, 7, 50
🟡 Warning [QA011] CASE 문에 ELSE 절 누락

카테고리: 안전성

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:17

설명: LOG_Parameter: CASE 문에 기본 처리(ELSE) 없음

⚠️ 위험성:

CASE ELSE 누락은 다음 위험을 야기합니다: - 예상치 못한 값 처리 불가 - 시스템 상태 불명확 - 디버깅 어려움 (어느 분기도 실행 안됨) - 안전 관련 동작 누락 가능 - 런타임 오류 발생 가능
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. ELSE 절 추가 (에러 처리)
   CASE state OF
       0: // 초기 상태
       1: // 실행 상태
       2: // 완료 상태
   ELSE
       // 예상치 못한 값
       errorFlag := TRUE;
       errorCode := 9999;
       state := 0;  // 안전 상태로 복귀
   END_CASE

2. 모든 가능한 값 명시 (열거형 사용)
   TYPE E_State : (INIT, RUNNING, COMPLETE);
   END_TYPE

   CASE state OF
       E_State.INIT: ...
       E_State.RUNNING: ...
       E_State.COMPLETE: ...
   ELSE
       // 방어 코드
   END_CASE

3. 로그 기록
   ELSE
       LogError('알 수 없는 상태: %d', state);
       state := E_State.INIT;
   END_CASE

예시:

❌ 위험한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
END_CASE // mode=3이면?

✅ 안전한 코드:
CASE mode OF
1: StartMotor();
2: StopMotor();
ELSE
errorFlag := TRUE;
EmergencyStop();
END_CASE
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: LOG_Process: 코드에 의미 불명확한 숫자 사용 (255, 11, 6, 3, 4, 5)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 255, 11, 6, 3, 4, 5
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:1

설명: SYS_LV_Log: 코드에 의미 불명확한 숫자 사용 (255, 5, 03581, 03582)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 255, 5, 03581, 03582
🟡 Warning [QA009] 중첩 구조가 너무 깊음

카테고리: 코드 복잡도

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:1

설명: SYS_LV_Log: 최대 6단계 중첩 (권장: 3단계 이하)

⚠️ 위험성:

깊은 중첩 구조는 다음 문제를 야기합니다: - 코드 이해 및 추적 어려움 - 순환 복잡도(Cyclomatic Complexity) 증가 - 버그 발생 가능성 증가 - 테스트 케이스 작성 어려움 - 유지보수 비용 증가
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. Early Return 패턴 사용
   ❌ IF condition1 THEN
          IF condition2 THEN
              IF condition3 THEN
                  // 작업
              END_IF
          END_IF
       END_IF

   ✅ IF NOT condition1 THEN RETURN; END_IF
      IF NOT condition2 THEN RETURN; END_IF
      IF NOT condition3 THEN RETURN; END_IF
      // 작업

2. 조건 결합
   ❌ IF a THEN
          IF b THEN
              // 작업
          END_IF
       END_IF

   ✅ IF a AND b THEN
          // 작업
       END_IF

3. 별도 함수로 추출
   IF ComplexCondition() THEN
       ProcessData();
   END_IF

   FUNCTION ComplexCondition : BOOL
       ComplexCondition := condition1 AND condition2;
   END_FUNCTION

4. 상태 머신으로 변환
   CASE state OF
       STATE_INIT: ...
       STATE_PROCESS: ...
       STATE_COMPLETE: ...
   END_CASE

예시:

현재 중첩 레벨: 6단계

리팩토링 예시:
// Early Return 사용
IF NOT sensorOK THEN
errorFlag := TRUE;
RETURN;
END_IF

IF NOT motorReady THEN
RETURN;
END_IF

// 정상 처리
ProcessData();
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivByte.TcPOU:1

설명: CheckDivByte: 코드에 의미 불명확한 숫자 사용 (03580)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 03580
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivDint.TcPOU:1

설명: CheckDivDint: 코드에 의미 불명확한 숫자 사용 (02598)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 02598
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivDWord.TcPOU:1

설명: CheckDivDWord: 코드에 의미 불명확한 숫자 사용 (02598)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 02598
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivInt.TcPOU:1

설명: CheckDivInt: 코드에 의미 불명확한 숫자 사용 (02598)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 02598
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivLreal.TcPOU:1

설명: CheckDivLreal: 코드에 의미 불명확한 숫자 사용 (02598)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 02598
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivReal.TcPOU:1

설명: CheckDivReal: 코드에 의미 불명확한 숫자 사용 (02598)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 02598
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivSInt.TcPOU:1

설명: CheckDivSInt: 코드에 의미 불명확한 숫자 사용 (02598)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 02598
🟡 Warning [QA007] 로직 내 매직 넘버 사용

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\CheckFunctions\CheckDivWord.TcPOU:1

설명: CheckDivWord: 코드에 의미 불명확한 숫자 사용 (02598)

⚠️ 위험성:

로직 내 매직 넘버는 유지보수를 어렵게 만듭니다: - 값 변경 시 모든 위치를 찾아 수정해야 함 - 같은 숫자라도 다른 의미일 수 있음 - 코드 리뷰 시 의도 파악 어려움
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 상수 정의
   VAR CONSTANT
       MAX_TEMPERATURE : REAL := 80.0;
       MIN_PRESSURE : REAL := 2.5;
   END_VAR

2. 로직에서 상수 사용
   IF temperature > MAX_TEMPERATURE THEN
       // 처리
   END_IF

3. 주석 추가 (임시 해결책)
   IF temperature > 80.0 THEN  // 최대 허용 온도 80도

예시:

매직 넘버 발견: 02598
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\stHeater_CtrlSet.TcDUT:1

설명: stHeater_CtrlSet: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\stHeater_Parameter_TableSet.TcDUT:1

설명: stHeater_Parameter_TableSet: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tCollection.TcDUT:1

설명: tCollection: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tLog.TcDUT:1

설명: tLog: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameterPartsPara.TcDUT:1

설명: tParameterPartsPara: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_Alarm.TcDUT:1

설명: tParameter_Alarm: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_Boat.TcDUT:1

설명: tParameter_Boat: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_CAL_PID.TcDUT:1

설명: tParameter_CAL_PID: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_FFU.TcDUT:1

설명: tParameter_FFU: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_FRPTV.TcDUT:1

설명: tParameter_FRPTV: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_Gas.TcDUT:1

설명: tParameter_Gas: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_Gas_Item.TcDUT:1

설명: tParameter_Gas_Item: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_Heater_ALARM.TcDUT:1

설명: tParameter_Heater_ALARM: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_Heater_AWC.TcDUT:1

설명: tParameter_Heater_AWC: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_Heater_FF_CTRL.TcDUT:1

설명: tParameter_Heater_FF_CTRL: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_Heater_ITD.TcDUT:1

설명: tParameter_Heater_ITD: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_Heater_PID.TcDUT:1

설명: tParameter_Heater_PID: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_Heater_POWER.TcDUT:1

설명: tParameter_Heater_POWER: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_Heater_RDNP.TcDUT:1

설명: tParameter_Heater_RDNP: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_Heater_Sub.TcDUT:1

설명: tParameter_Heater_Sub: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_Heater_TC.TcDUT:1

설명: tParameter_Heater_TC: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_Intensity_Range.TcDUT:1

설명: tParameter_Intensity_Range: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_LH_ALARM.TcDUT:1

설명: tParameter_LH_ALARM: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_LH_PID.TcDUT:1

설명: tParameter_LH_PID: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_LH_SET.TcDUT:1

설명: tParameter_LH_SET: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_Pressure_Range.TcDUT:1

설명: tParameter_Pressure_Range: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_ProfileTune.TcDUT:1

설명: tParameter_ProfileTune: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_RDNPTune.TcDUT:1

설명: tParameter_RDNPTune: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_RSD.TcDUT:1

설명: tParameter_RSD: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_Scale.TcDUT:1

설명: tParameter_Scale: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tParameter_TempTarget.TcDUT:1

설명: tParameter_TempTarget: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tRecipe.TcDUT:1

설명: tRecipe: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\tRecipeBody.TcDUT:1

설명: tRecipeBody: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\t_Gas.TcDUT:1

설명: t_Gas: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\t_Heater_ALARM.TcDUT:1

설명: t_Heater_ALARM: 구조체는 'ST_' 또는 'T_' 접두사 사용 권장 (예: ST_SensorData)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eCtrl.TcDUT:1

설명: eCtrl: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Alarm_HeaterPower.TcDUT:1

설명: eDesc_Alarm_HeaterPower: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Alarm_Level.TcDUT:1

설명: eDesc_Alarm_Level: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Alarm_ProcessAction.TcDUT:1

설명: eDesc_Alarm_ProcessAction: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Alarm_Use.TcDUT:1

설명: eDesc_Alarm_Use: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Autocal_Type.TcDUT:1

설명: eDesc_Autocal_Type: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_AutoProfile_Target.TcDUT:3

설명: eDesc_AutoProfile_Target: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_AutoTune_Result.TcDUT:1

설명: eDesc_AutoTune_Result: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_AWC_Mode.TcDUT:1

설명: eDesc_AWC_Mode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_CAS_Tune_Mode.TcDUT:1

설명: eDesc_CAS_Tune_Mode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Check_Mode.TcDUT:3

설명: eDesc_Check_Mode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Driver_CommStatus.TcDUT:1

설명: eDesc_Driver_CommStatus: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Driver_Status.TcDUT:1

설명: eDesc_Driver_Status: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Exception.TcDUT:1

설명: eDesc_Exception: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_FRPTV_Abort_Action.TcDUT:1

설명: eDesc_FRPTV_Abort_Action: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Glass.TcDUT:1

설명: eDesc_Glass: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Heater_Alarm.TcDUT:1

설명: eDesc_Heater_Alarm: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Heater_Command.TcDUT:1

설명: eDesc_Heater_Command: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Heater_CtrlMode.TcDUT:1

설명: eDesc_Heater_CtrlMode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Heater_CtrlOption.TcDUT:1

설명: eDesc_Heater_CtrlOption: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Heater_Mode.TcDUT:1

설명: eDesc_Heater_Mode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Heater_OutMode.TcDUT:1

설명: eDesc_Heater_OutMode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Heater_Zone.TcDUT:1

설명: eDesc_Heater_Zone: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Interlock_Value.TcDUT:1

설명: eDesc_Interlock_Value: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_ITD_Mode.TcDUT:1

설명: eDesc_ITD_Mode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_LV_Ctrl_Mode.TcDUT:1

설명: eDesc_LV_Ctrl_Mode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_LV_Group.TcDUT:1

설명: eDesc_LV_Group: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_LV_Status.TcDUT:1

설명: eDesc_LV_Status: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_MFC_Check.TcDUT:1

설명: eDesc_MFC_Check: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_MFC_Maker.TcDUT:1

설명: eDesc_MFC_Maker: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_O2AnalyzerMaker.TcDUT:3

설명: eDesc_O2AnalyzerMaker: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_O2Cal_Command.TcDUT:1

설명: eDesc_O2Cal_Command: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_PartsPara.TcDUT:1

설명: eDesc_PartsPara: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_PID_Table.TcDUT:1

설명: eDesc_PID_Table: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Pump.TcDUT:1

설명: eDesc_Pump: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Ratio_Mode.TcDUT:1

설명: eDesc_Ratio_Mode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Select_AlarmTable.TcDUT:1

설명: eDesc_Select_AlarmTable: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Slot.TcDUT:1

설명: eDesc_Slot: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Source.TcDUT:1

설명: eDesc_Source: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Start_Stop.TcDUT:1

설명: eDesc_Start_Stop: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_BE_Moving.TcDUT:1

설명: eDesc_State_BE_Moving: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_Boat.TcDUT:1

설명: eDesc_State_Boat: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_Boat_TCPIP.TcDUT:1

설명: eDesc_State_Boat_TCPIP: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_Charge.TcDUT:1

설명: eDesc_State_Charge: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_DIPAS.TcDUT:1

설명: eDesc_State_DIPAS: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_Elevator.TcDUT:1

설명: eDesc_State_Elevator: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_Elevator_Mode.TcDUT:1

설명: eDesc_State_Elevator_Mode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_FFU_Condition.TcDUT:1

설명: eDesc_State_FFU_Condition: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_FP_STS.TcDUT:1

설명: eDesc_State_FP_STS: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_Ionizer.TcDUT:1

설명: eDesc_State_Ionizer: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_LoadLock.TcDUT:1

설명: eDesc_State_LoadLock: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_MFC.TcDUT:1

설명: eDesc_State_MFC: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_Module.TcDUT:1

설명: eDesc_State_Module: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_PG.TcDUT:1

설명: eDesc_State_PG: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_Pressure.TcDUT:1

설명: eDesc_State_Pressure: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_Pressure_Check.TcDUT:1

설명: eDesc_State_Pressure_Check: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_Process.TcDUT:1

설명: eDesc_State_Process: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_Process_Loop.TcDUT:1

설명: eDesc_State_Process_Loop: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_PS.TcDUT:1

설명: eDesc_State_PS: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_Ready.TcDUT:1

설명: eDesc_State_Ready: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_Robot.TcDUT:1

설명: eDesc_State_Robot: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_Shutter.TcDUT:1

설명: eDesc_State_Shutter: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_Temp_Button.TcDUT:1

설명: eDesc_State_Temp_Button: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_Valve.TcDUT:1

설명: eDesc_State_Valve: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_State_WTR_Moving.TcDUT:1

설명: eDesc_State_WTR_Moving: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Table.TcDUT:1

설명: eDesc_Table: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_TempCondition_Target.TcDUT:3

설명: eDesc_TempCondition_Target: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_TempEndTarget.TcDUT:3

설명: eDesc_TempEndTarget: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Temp_Check_Target.TcDUT:1

설명: eDesc_Temp_Check_Target: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Time_Unit.TcDUT:1

설명: eDesc_Time_Unit: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Unit.TcDUT:1

설명: eDesc_Unit: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Usable.TcDUT:1

설명: eDesc_Usable: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Use.TcDUT:1

설명: eDesc_Use: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Wafer_Charge_Check.TcDUT:1

설명: eDesc_Wafer_Charge_Check: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDesc_Wafer_Move_Condition.TcDUT:1

설명: eDesc_Wafer_Move_Condition: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDriver_APC.TcDUT:1

설명: eDriver_APC: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDriver_Boat_Elevator.TcDUT:1

설명: eDriver_Boat_Elevator: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDriver_Boat_Rotation.TcDUT:1

설명: eDriver_Boat_Rotation: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDriver_EtherCat_APC.TcDUT:1

설명: eDriver_EtherCat_APC: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDriver_FFU.TcDUT:1

설명: eDriver_FFU: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDriver_FFU_ModBus.TcDUT:1

설명: eDriver_FFU_ModBus: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDriver_MFC_Mode.TcDUT:1

설명: eDriver_MFC_Mode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDriver_ModBus.TcDUT:1

설명: eDriver_ModBus: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDriver_TV_VAT.TcDUT:1

설명: eDriver_TV_VAT: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eDriver_VG.TcDUT:1

설명: eDriver_VG: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eIndex_Gas.TcDUT:3

설명: eIndex_Gas: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eIndex_MFC.TcDUT:4

설명: eIndex_MFC: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eIndex_RSD.TcDUT:3

설명: eIndex_RSD: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eIndex_Valve.TcDUT:4

설명: eIndex_Valve: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_ATM_Sensor.TcDUT:1

설명: eMode_ATM_Sensor: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_AutoRefill.TcDUT:1

설명: eMode_AutoRefill: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_FRPTV.TcDUT:1

설명: eMode_FRPTV: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_APC.TcDUT:1

설명: eMode_Function_APC: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_APC_APC.TcDUT:1

설명: eMode_Function_APC_APC: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_Auto_BLoad_Tune.TcDUT:1

설명: eMode_Function_Auto_BLoad_Tune: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_Auto_Tune.TcDUT:1

설명: eMode_Function_Auto_Tune: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_Boat_Elevator.TcDUT:1

설명: eMode_Function_Boat_Elevator: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_Boat_Rotation.TcDUT:1

설명: eMode_Function_Boat_Rotation: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_Door.TcDUT:1

설명: eMode_Function_Door: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_LV_Sensor.TcDUT:1

설명: eMode_Function_LV_Sensor: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_Off_On.TcDUT:1

설명: eMode_Function_Off_On: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_PartsPara.TcDUT:1

설명: eMode_Function_PartsPara: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_PID_Tune.TcDUT:1

설명: eMode_Function_PID_Tune: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_Process.TcDUT:1

설명: eMode_Function_Process: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_RSD.TcDUT:1

설명: eMode_Function_RSD: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_SdoMfc.TcDUT:1

설명: eMode_Function_SdoMfc: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_Shutter.TcDUT:1

설명: eMode_Function_Shutter: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_TV.TcDUT:1

설명: eMode_Function_TV: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_TVLPV.TcDUT:1

설명: eMode_Function_TVLPV: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_TV_VAT.TcDUT:1

설명: eMode_Function_TV_VAT: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_Vacuum.TcDUT:1

설명: eMode_Function_Vacuum: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Function_VG.TcDUT:1

설명: eMode_Function_VG: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Interface.TcDUT:1

설명: eMode_Interface: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Ionizer.TcDUT:1

설명: eMode_Ionizer: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_LoadLock.TcDUT:1

설명: eMode_LoadLock: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_O3_Generator.TcDUT:1

설명: eMode_O3_Generator: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Rotate_Direction.TcDUT:1

설명: eMode_Rotate_Direction: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Stable_Check.TcDUT:1

설명: eMode_Stable_Check: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eMode_Stable_O2_Check.TcDUT:1

설명: eMode_Stable_O2_Check: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eRcp_ApcMode.TcDUT:3

설명: eRcp_ApcMode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eRcp_Condition.TcDUT:3

설명: eRcp_Condition: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eRcp_ConditionItem.TcDUT:3

설명: eRcp_ConditionItem: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eRcp_DcopMode.TcDUT:3

설명: eRcp_DcopMode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eRcp_ElevatorMode.TcDUT:3

설명: eRcp_ElevatorMode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eRcp_ElevatorSpeedType.TcDUT:3

설명: eRcp_ElevatorSpeedType: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eRcp_FrpMode.TcDUT:3

설명: eRcp_FrpMode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eRcp_HeaterMode.TcDUT:3

설명: eRcp_HeaterMode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eRcp_LoadlockMode.TcDUT:3

설명: eRcp_LoadlockMode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eRcp_PressureCheck.TcDUT:3

설명: eRcp_PressureCheck: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eRcp_StsMode.TcDUT:3

설명: eRcp_StsMode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eRcp_TempTune.TcDUT:3

설명: eRcp_TempTune: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eRcp_TV55Mode.TcDUT:3

설명: eRcp_TV55Mode: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eRcp_TvTable.TcDUT:3

설명: eRcp_TvTable: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🟡 Warning [QA012] 데이터 타입 명명 규칙 위반

카테고리: 명명 규칙

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\Data types\eRcp_Type.TcDUT:3

설명: eRcp_Type: 열거형은 'E_' 접두사 사용 권장 (예: E_MotorState)

⚠️ 위험성:

데이터 타입 명명 규칙 위반은 타입 식별을 어렵게 만듭니다.
💡 권장 해결 방법:
권장 접두사:
- 구조체: ST_ (예: ST_SensorData)
- 열거형: E_ (예: E_MotorState)
- 함수 블록: FB_ (예: FB_Controller)
- 일반 타입: T_ (예: T_CustomArray)
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\MAIN_10ms.TcPOU:1

설명: MAIN_10ms: 36줄 중 주석 0개 (권장: 2개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 36줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(2개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: FindValue_Inverse_TempParaTable: 63줄 중 주석 1개 (권장: 4개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 63줄의 코드에 1개의 주석만 있어, 20줄당 1개 기준(4개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_Inverse_TempParaTable.TcPOU:1

설명: FindValue_Inverse_TempParaTable: 순환 복잡도 18 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 18로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 18개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: FindValue_TempParaTable: 63줄 중 주석 1개 (권장: 4개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 63줄의 코드에 1개의 주석만 있어, 20줄당 1개 기준(4개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\FindValue_TempParaTable.TcPOU:1

설명: FindValue_TempParaTable: 순환 복잡도 18 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 18로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 18개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Add_EventLog_buffer.TcPOU:1

설명: F_Add_EventLog_buffer: 45줄 중 주석 1개 (권장: 3개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 45줄의 코드에 1개의 주석만 있어, 20줄당 1개 기준(3개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: F_Cycle_StepCount: 71줄 중 주석 2개 (권장: 4개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 71줄의 코드에 2개의 주석만 있어, 20줄당 1개 기준(4개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount.TcPOU:1

설명: F_Cycle_StepCount: 파라미터 5개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 5개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: F_Cycle_StepCount_1: 71줄 중 주석 2개 (권장: 4개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 71줄의 코드에 2개의 주석만 있어, 20줄당 1개 기준(4개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Cycle_StepCount_1.TcPOU:1

설명: F_Cycle_StepCount_1: 파라미터 5개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 5개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_APC_PID.TcPOU:1

설명: F_Driver_APC_PID: 25줄 중 주석 0개 (권장: 2개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 25줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(2개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Boat_Elevator.TcPOU:1

설명: F_Driver_Boat_Elevator: 32줄 중 주석 0개 (권장: 2개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 32줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(2개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Driver_Heater_Extract_Array.TcPOU:1

설명: F_Driver_Heater_Extract_Array: 29줄 중 주석 1개 (권장: 2개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 29줄의 코드에 1개의 주석만 있어, 20줄당 1개 기준(2개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_EventLog_Shift.TcPOU:1

설명: F_EventLog_Shift: 24줄 중 주석 0개 (권장: 2개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 24줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(2개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Func.TcPOU:1

설명: F_MarsLog_Func: 41줄 중 주석 0개 (권장: 3개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 41줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(3개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_MarsLog_Process.TcPOU:1

설명: F_MarsLog_Process: 72줄 중 주석 1개 (권장: 4개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 72줄의 코드에 1개의 주석만 있어, 20줄당 1개 기준(4개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Parameter_Check.TcPOU:1

설명: F_Parameter_Check: 28줄 중 주석 0개 (권장: 2개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 28줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(2개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_Set_Parameter.TcPOU:1

설명: F_Set_Parameter: 32줄 중 주석 0개 (권장: 2개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 32줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(2개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\F_StepName_Search.TcPOU:1

설명: F_StepName_Search: 24줄 중 주석 0개 (권장: 2개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 24줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(2개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function\Get_IEEE754.TcPOU:1

설명: Get_IEEE754: 22줄 중 주석 0개 (권장: 2개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 22줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(2개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: FB_Alarm: 101줄 중 주석 2개 (권장: 6개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 101줄의 코드에 2개의 주석만 있어, 20줄당 1개 기준(6개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: FB_Alarm: 순환 복잡도 25 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 25로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 25개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Alarm.TcPOU:1

설명: FB_Alarm: 파라미터 5개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 5개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_BasicPID_RSD.TcPOU:1

설명: FB_BasicPID_RSD: 파라미터 9개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 9개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Collection.TcPOU:1

설명: FB_Collection: 56줄 중 주석 0개 (권장: 3개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 56줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(3개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: FB_Control_Gas: 112줄 중 주석 1개 (권장: 6개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 112줄의 코드에 1개의 주석만 있어, 20줄당 1개 기준(6개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Gas.TcPOU:1

설명: FB_Control_Gas: 파라미터 25개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 25개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Control_Pump.TcPOU:1

설명: FB_Control_Pump: 40줄 중 주석 0개 (권장: 2개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 40줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(2개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_EXPLICT_MESSAGE.TcPOU:1

설명: FB_EXPLICT_MESSAGE: 파라미터 9개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 9개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Heater_Group_Scan.TcPOU:1

설명: FB_Interlock_Heater_Group_Scan: 29줄 중 주석 0개 (권장: 2개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 29줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(2개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal.TcPOU:1

설명: FB_Interlock_Signal: 37줄 중 주석 1개 (권장: 2개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 37줄의 코드에 1개의 주석만 있어, 20줄당 1개 기준(2개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_BurnBox.TcPOU:1

설명: FB_Interlock_Signal_BurnBox: 31줄 중 주석 0개 (권장: 2개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 31줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(2개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_Temp.TcPOU:1

설명: FB_Interlock_Signal_Temp: 40줄 중 주석 1개 (권장: 2개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 40줄의 코드에 1개의 주석만 있어, 20줄당 1개 기준(2개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Signal_Temp.TcPOU:1

설명: FB_Interlock_Signal_Temp: 파라미터 5개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 5개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_TempDelay.TcPOU:1

설명: FB_Interlock_TempDelay: 25줄 중 주석 0개 (권장: 2개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 25줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(2개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: FB_Interlock_Valve: 80줄 중 주석 0개 (권장: 4개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 80줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(4개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: FB_Interlock_Valve: 순환 복잡도 15 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 15로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 15개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Interlock_Valve.TcPOU:1

설명: FB_Interlock_Valve: 파라미터 6개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 6개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:1

설명: FB_Sdo_Gas: 104줄 중 주석 3개 (권장: 6개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 104줄의 코드에 3개의 주석만 있어, 20줄당 1개 기준(6개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas.TcPOU:1

설명: FB_Sdo_Gas: 파라미터 13개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 13개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Sdo_Gas_PartsPara.TcPOU:1

설명: FB_Sdo_Gas_PartsPara: 파라미터 5개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 5개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Signal_2BYTE.TcPOU:1

설명: FB_Signal_2BYTE: 22줄 중 주석 0개 (권장: 2개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 22줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(2개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:1

설명: FB_Temp_DEV_And_Short: 72줄 중 주석 3개 (권장: 4개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 72줄의 코드에 3개의 주석만 있어, 20줄당 1개 기준(4개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_And_Short.TcPOU:1

설명: FB_Temp_DEV_And_Short: 파라미터 9개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 9개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:1

설명: FB_Temp_DEV_Zone_to_Zone: 55줄 중 주석 0개 (권장: 3개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 55줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(3개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone.TcPOU:1

설명: FB_Temp_DEV_Zone_to_Zone: 파라미터 7개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 7개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:1

설명: FB_Temp_DEV_Zone_to_Zone_Option: 62줄 중 주석 0개 (권장: 4개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 62줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(4개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Temp_DEV_Zone_to_Zone_Option.TcPOU:1

설명: FB_Temp_DEV_Zone_to_Zone_Option: 파라미터 10개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 10개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Timer.TcPOU:1

설명: FB_Timer: 27줄 중 주석 1개 (권장: 2개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 27줄의 코드에 1개의 주석만 있어, 20줄당 1개 기준(2개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA020] 들여쓰기 스타일 혼용으로 인한 일관성 저하

카테고리: 코드 스타일

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_VG_Cal.TcPOU:1

설명: FB_VG_Cal: TAB 87줄, SPACE 1줄 혼용

⚠️ 위험성:

들여쓰기 스타일이 혼용되어 다음 문제가 발생합니다: 1. 가독성 저하: 편집기마다 다르게 표시됨 2. 버전 관리 충돌: 불필요한 diff 발생 3. 코드 정렬 혼란: 탭과 스페이스 너비 차이로 정렬 깨짐 4. 협업 어려움: 팀원마다 다른 설정으로 혼란 통계: - TAB 들여쓰기: 87줄 - SPACE 들여쓰기: 1줄 - 혼용 비율: 1.1% 일관된 스타일을 선택하고 프로젝트 전체에 적용해야 합니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 프로젝트 스타일 가이드 정의
   // .editorconfig 파일 생성
   [*.TcPOU]
   indent_style = tab
   indent_size = 4

   또는

   [*.TcPOU]
   indent_style = space
   indent_size = 4

2. Visual Studio/TwinCAT 설정 통일
   도구 → 옵션 → 텍스트 편집기 → 모든 언어
   - 탭 사용 또는 스페이스 사용 선택
   - 팀 전체가 동일 설정 사용

3. 자동 포맷팅 도구 사용
   - 코드 정리 기능 활용 (Ctrl+K, Ctrl+D)
   - 저장 시 자동 포맷팅 설정

4. 기존 코드 일괄 변환
   // TAB → SPACE 변환
   편집 → 고급 → 공백을 탭으로 변환

   // SPACE → TAB 변환
   편집 → 고급 → 탭을 공백으로 변환

5. Git hooks 활용
   // pre-commit hook으로 스타일 검사
   #!/bin/sh
   # 혼용 감지 스크립트 실행

권장 스타일:
- IEC 61131-3 표준: TAB (4칸)
- 대부분의 PLC 환경: TAB 사용이 일반적

예시:

// ❌ 스타일 혼용 (보이지 않음)
FUNCTION_BLOCK FB_Example
VAR
var1 : INT; // TAB으로 들여쓰기
var2 : INT; // SPACE로 들여쓰기 (4칸)
var3 : INT; // TAB 2개
var4 : INT;// SPACE 8칸
END_VAR

// ✅ 일관된 스타일 (TAB)
FUNCTION_BLOCK FB_Example
VAR
var1 : INT;
var2 : INT;
var3 : INT;
var4 : INT;
END_VAR

// ✅ 일관된 스타일 (SPACE 4칸)
FUNCTION_BLOCK FB_Example
VAR
var1 : INT;
var2 : INT;
var3 : INT;
var4 : INT;
END_VAR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:1

설명: FB_Warn_Alarm_Rang_Signal: 58줄 중 주석 0개 (권장: 3개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 58줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(3개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal.TcPOU:1

설명: FB_Warn_Alarm_Rang_Signal: 파라미터 6개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 6개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig.TcPOU:1

설명: FB_Warn_Alarm_Rang_Signal_Trig: 46줄 중 주석 0개 (권장: 3개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 46줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(3개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig.TcPOU:1

설명: FB_Warn_Alarm_Rang_Signal_Trig: 파라미터 6개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 6개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig_Sign.TcPOU:1

설명: FB_Warn_Alarm_Rang_Signal_Trig_Sign: 46줄 중 주석 0개 (권장: 3개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 46줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(3개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Function Block\FB_Warn_Alarm_Rang_Signal_Trig_Sign.TcPOU:1

설명: FB_Warn_Alarm_Rang_Signal_Trig_Sign: 파라미터 6개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 6개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:1

설명: SEQ_Driver_APC: 125줄 중 주석 0개 (권장: 7개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 125줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(7개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_APC.TcPOU:1

설명: SEQ_Driver_APC: 파라미터 16개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 16개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_FFU_EtherCAT.TcPOU:1

설명: SEQ_Driver_FFU_EtherCAT: 순환 복잡도 22 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 22로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 22개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_O2Analyzer.TcPOU:1

설명: SEQ_Driver_O2Analyzer: 123줄 중 주석 5개 (권장: 7개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 123줄의 코드에 5개의 주석만 있어, 20줄당 1개 기준(7개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: SEQ_Driver_SdoMfc: 122줄 중 주석 2개 (권장: 7개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 122줄의 코드에 2개의 주석만 있어, 20줄당 1개 기준(7개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_SdoMfc.TcPOU:1

설명: SEQ_Driver_SdoMfc: 순환 복잡도 16 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 16로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 16개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:1

설명: SEQ_Driver_TCPIP: 134줄 중 주석 4개 (권장: 7개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 134줄의 코드에 4개의 주석만 있어, 20줄당 1개 기준(7개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TCPIP.TcPOU:1

설명: SEQ_Driver_TCPIP: 파라미터 15개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 15개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TVLPV.TcPOU:1

설명: SEQ_Driver_TVLPV: 순환 복잡도 20 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 20로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 20개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: SEQ_Driver_TV_VAT: 121줄 중 주석 2개 (권장: 7개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 121줄의 코드에 2개의 주석만 있어, 20줄당 1개 기준(7개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_TV_VAT.TcPOU:1

설명: SEQ_Driver_TV_VAT: 순환 복잡도 25 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 25로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 25개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Driver_VG.TcPOU:1

설명: SEQ_Driver_VG: 순환 복잡도 16 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 16로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 16개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: SEQ_Function_Auto_PID: 122줄 중 주석 4개 (권장: 7개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 122줄의 코드에 4개의 주석만 있어, 20줄당 1개 기준(7개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_PID.TcPOU:1

설명: SEQ_Function_Auto_PID: 순환 복잡도 21 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 21로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 21개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_Profile.TcPOU:1

설명: SEQ_Function_Auto_Profile: 121줄 중 주석 5개 (권장: 7개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 121줄의 코드에 5개의 주석만 있어, 20줄당 1개 기준(7개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Auto_RDNP.TcPOU:1

설명: SEQ_Function_Auto_RDNP: 순환 복잡도 24 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 24로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 24개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_PartsPara.TcPOU:1

설명: SEQ_Function_PartsPara: 순환 복잡도 19 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 19로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 19개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Function_Process.TcPOU:1

설명: SEQ_Function_Process: 113줄 중 주석 0개 (권장: 6개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 113줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(6개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interface.TcPOU:1

설명: SEQ_Interface: 순환 복잡도 45 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 45로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 45개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Interlock_Valve.TcPOU:1

설명: SEQ_Interlock_Valve: 91줄 중 주석 1개 (권장: 5개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 91줄의 코드에 1개의 주석만 있어, 20줄당 1개 기준(5개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: SEQ_Physical_APC: 116줄 중 주석 1개 (권장: 6개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 116줄의 코드에 1개의 주석만 있어, 20줄당 1개 기준(6개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_APC.TcPOU:1

설명: SEQ_Physical_APC: 순환 복잡도 36 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 36로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 36개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Elevator.TcPOU:1

설명: SEQ_Physical_Boat_Elevator: 순환 복잡도 22 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 22로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 22개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: SEQ_Physical_Boat_Rotation: 137줄 중 주석 4개 (권장: 7개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 137줄의 코드에 4개의 주석만 있어, 20줄당 1개 기준(7개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Boat_Rotation.TcPOU:1

설명: SEQ_Physical_Boat_Rotation: 순환 복잡도 34 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 34로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 34개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: SEQ_Physical_FRPTV: 149줄 중 주석 3개 (권장: 8개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 149줄의 코드에 3개의 주석만 있어, 20줄당 1개 기준(8개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_FRPTV.TcPOU:1

설명: SEQ_Physical_FRPTV: 순환 복잡도 23 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 23로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 23개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_GFC.TcPOU:1

설명: SEQ_Physical_GFC: 77줄 중 주석 1개 (권장: 4개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 77줄의 코드에 1개의 주석만 있어, 20줄당 1개 기준(4개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_Heater_Shutter.TcPOU:1

설명: SEQ_Physical_Heater_Shutter: 순환 복잡도 20 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 20로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 20개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LoadLock.TcPOU:1

설명: SEQ_Physical_LoadLock: 순환 복잡도 29 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 29로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 29개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_LPV.TcPOU:1

설명: SEQ_Physical_LPV: 순환 복잡도 26 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 26로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 26개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: SEQ_Physical_RSD: 105줄 중 주석 1개 (권장: 6개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 105줄의 코드에 1개의 주석만 있어, 20줄당 1개 기준(6개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_RSD.TcPOU:1

설명: SEQ_Physical_RSD: 순환 복잡도 18 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 18로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 18개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_TV_VAT.TcPOU:1

설명: SEQ_Physical_TV_VAT: 순환 복잡도 24 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 24로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 24개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: SEQ_Physical_VG01: 121줄 중 주석 4개 (권장: 7개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 121줄의 코드에 4개의 주석만 있어, 20줄당 1개 기준(7개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG01.TcPOU:1

설명: SEQ_Physical_VG01: 순환 복잡도 20 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 20로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 20개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: SEQ_Physical_VG02: 121줄 중 주석 4개 (권장: 7개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 121줄의 코드에 4개의 주석만 있어, 20줄당 1개 기준(7개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG02.TcPOU:1

설명: SEQ_Physical_VG02: 순환 복잡도 21 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 21로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 21개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: SEQ_Physical_VG03: 94줄 중 주석 4개 (권장: 5개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 94줄의 코드에 4개의 주석만 있어, 20줄당 1개 기준(5개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG03.TcPOU:1

설명: SEQ_Physical_VG03: 순환 복잡도 16 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 16로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 16개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: SEQ_Physical_VG04: 94줄 중 주석 4개 (권장: 5개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 94줄의 코드에 4개의 주석만 있어, 20줄당 1개 기준(5개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG04.TcPOU:1

설명: SEQ_Physical_VG04: 순환 복잡도 16 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 16로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 16개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: SEQ_Physical_VG05: 94줄 중 주석 4개 (권장: 5개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 94줄의 코드에 4개의 주석만 있어, 20줄당 1개 기준(5개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\Sequence\SEQ_Physical_VG05.TcPOU:1

설명: SEQ_Physical_VG05: 순환 복잡도 16 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 16로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 16개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_DataExchange.TcPOU:1

설명: SYS_DataExchange: 순환 복잡도 24 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 24로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 24개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Input.TcPOU:1

설명: SYS_Input: 163줄 중 주석 3개 (권장: 9개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 163줄의 코드에 3개의 주석만 있어, 20줄당 1개 기준(9개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: SYS_MFC_Self_Diagnosis: 125줄 중 주석 2개 (권장: 7개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 125줄의 코드에 2개의 주석만 있어, 20줄당 1개 기준(7개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_MFC_Self_Diagnosis.TcPOU:1

설명: SYS_MFC_Self_Diagnosis: 순환 복잡도 17 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 17로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 17개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_Output.TcPOU:1

설명: SYS_Output: 84줄 중 주석 3개 (권장: 5개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 84줄의 코드에 3개의 주석만 있어, 20줄당 1개 기준(5개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: SYS_TrendLog: 117줄 중 주석 1개 (권장: 6개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 117줄의 코드에 1개의 주석만 있어, 20줄당 1개 기준(6개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\System\SYS_TrendLog.TcPOU:1

설명: SYS_TrendLog: 순환 복잡도 23 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 23로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 23개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:1

설명: FB_Temp_Control: 98줄 중 주석 0개 (권장: 5개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 98줄의 코드에 0개의 주석만 있어, 20줄당 1개 기준(5개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Control.TcPOU:1

설명: FB_Temp_Control: 파라미터 8개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 8개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:1

설명: FB_Temp_Simulator: 42줄 중 주석 2개 (권장: 3개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 42줄의 코드에 2개의 주석만 있어, 20줄당 1개 기준(3개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA018] 파라미터 과다로 인한 가독성 및 유지보수성 저하

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\FB_Temp_Simulator.TcPOU:1

설명: FB_Temp_Simulator: 파라미터 6개 (권장: 5개 미만)

⚠️ 위험성:

파라미터가 6개로 많아 다음 문제가 발생합니다: 1. 가독성 저하: 함수 호출 시 인자 순서 파악이 어려움 2. 오류 가능성: 파라미터 순서 착오로 인한 버그 발생 3. 유지보수 어려움: 파라미터 추가/제거 시 모든 호출부 수정 필요 4. 테스트 복잡도: 조합 경우의 수가 기하급수적으로 증가 일반적으로 3-4개 이하의 파라미터가 이상적이며, 5개 이상이면 구조체로 그룹화하는 것이 좋습니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 구조체로 파라미터 그룹화
   TYPE ST_MotorConfig :
   STRUCT
       speed : REAL;           // 속도 [rpm]
       acceleration : REAL;    // 가속도 [rpm/s]
       maxCurrent : REAL;      // 최대 전류 [A]
       direction : BOOL;       // 방향 (0:CW, 1:CCW)
       enableBrake : BOOL;     // 브레이크 활성화
   END_STRUCT
   END_TYPE

   // 변경 전: 파라미터 5개
   METHOD ConfigureMotor(speed, accel, current, dir, brake)

   // 변경 후: 구조체 1개
   METHOD ConfigureMotor(config : ST_MotorConfig)

2. 관련 파라미터를 의미 단위로 그룹화
   TYPE ST_InputSignals :
   STRUCT
       sensor1 : BOOL;
       sensor2 : BOOL;
       sensor3 : BOOL;
   END_STRUCT
   END_TYPE

3. Builder 패턴 고려 (복잡한 설정의 경우)
   config.SetSpeed(1000.0)
         .SetAcceleration(500.0)
         .SetDirection(TRUE)
         .Build();

예시:

// ❌ 파라미터가 너무 많음
FUNCTION_BLOCK FB_Motor
VAR_INPUT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_VAR

// ✅ 구조체로 개선
TYPE ST_MotorParams :
STRUCT
targetSpeed : REAL;
acceleration : REAL;
maxCurrent : REAL;
direction : BOOL;
enableBrake : BOOL;
enableMonitoring : BOOL;
END_STRUCT
END_TYPE

FUNCTION_BLOCK FB_Motor
VAR_INPUT
params : ST_MotorParams; // 명확하고 확장 가능
END_VAR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs\TempController\SEQ_Driver_Mini8_ModBusTCP.TcPOU:1

설명: SEQ_Driver_Mini8_ModBusTCP: 135줄 중 주석 3개 (권장: 7개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 135줄의 코드에 3개의 주석만 있어, 20줄당 1개 기준(7개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Function\F_TrendData_RealToString.TcPOU:1

설명: F_TrendData_RealToString: 순환 복잡도 26 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 26로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 26개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Dcoll.TcPOU:1

설명: LOG_Dcoll: 111줄 중 주석 2개 (권장: 6개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 111줄의 코드에 2개의 주석만 있어, 20줄당 1개 기준(6개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Event.TcPOU:1

설명: LOG_Event: 순환 복잡도 17 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 17로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 17개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Mars.TcPOU:1

설명: LOG_Mars: 126줄 중 주석 2개 (권장: 7개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 126줄의 코드에 2개의 주석만 있어, 20줄당 1개 기준(7개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: LOG_Parameter: 139줄 중 주석 4개 (권장: 7개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 139줄의 코드에 4개의 주석만 있어, 20줄당 1개 기준(7개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Parameter.TcPOU:1

설명: LOG_Parameter: 순환 복잡도 15 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 15로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 15개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: LOG_Process: 134줄 중 주석 1개 (권장: 7개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 134줄의 코드에 1개의 주석만 있어, 20줄당 1개 기준(7개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\LOG_Process.TcPOU:1

설명: LOG_Process: 순환 복잡도 16 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 16로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 16개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_LV_Log.TcPOU:1

설명: SYS_LV_Log: 127줄 중 주석 2개 (권장: 7개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 127줄의 코드에 2개의 주석만 있어, 20줄당 1개 기준(7개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA016] 주석 부족으로 인한 가독성 저하 가능

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: SYS_Signal: 142줄 중 주석 4개 (권장: 8개 이상)

⚠️ 위험성:

주석이 부족하면 코드 이해와 유지보수가 어려워집니다. 현재 142줄의 코드에 4개의 주석만 있어, 20줄당 1개 기준(8개)에 미달합니다. 특히 복잡한 로직이나 알고리즘의 경우 주석이 필수적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 복잡한 로직 설명 추가
   // 센서 값을 읽어 이동평균 필터 적용
   filteredValue := (value1 + value2 + value3) / 3;

2. 중요한 변수 의미 설명
   // 최대 속도 제한값 [mm/s]
   maxSpeed := 1000.0;

3. 알고리즘 의도 명시
   // PID 제어: 목표값과 현재값의 오차를 줄임
   error := setpoint - processValue;

4. 주석 작성 가이드라인
   - 함수/FB 상단: 목적과 동작 설명
   - 복잡한 수식: 물리적 의미 설명
   - 매직 넘버: 값의 근거 설명
   - 상태 전환: 전환 조건 설명

예시:

// ❌ 주석 부족
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2;
IF sum > 100 THEN
flag := TRUE;
END_IF
END_FOR

// ✅ 적절한 주석
// 배열 값을 2배로 증폭하여 합산
FOR i := 1 TO 10 DO
sum := sum + arr[i] * 2; // 신호 증폭 계수 2.0
// 합계가 임계값 초과 시 플래그 설정
IF sum > 100 THEN
flag := TRUE; // 알람 트리거
END_IF
END_FOR
🔵 Info [QA017] 높은 순환 복잡도로 인한 유지보수 어려움

카테고리: 코드 품질

📍 D:\00.Comapre\pollux_hcds_ald_mirror\Src_Diff\PLC\PM1\PM1\POLY\POUs_10ms\Sequence\SYS_Signal.TcPOU:1

설명: SYS_Signal: 순환 복잡도 31 (권장: 15 미만)

⚠️ 위험성:

순환 복잡도가 31로 매우 높아 다음 문제가 발생할 수 있습니다: 1. 테스트 어려움: 31개 이상의 경로를 테스트해야 함 2. 버그 발생률 증가: 복잡도가 높을수록 버그 가능성 증가 3. 이해 난이도 상승: 코드 흐름 파악이 어려움 4. 변경 위험: 수정 시 예상치 못한 부작용 발생 가능 권장 복잡도는 15 미만이며, 10 이하가 이상적입니다.
💡 권장 해결 방법:
✅ 권장 해결 방법:

1. 함수 분할
   // 복잡한 함수를 여러 개의 작은 함수로 분리
   FUNCTION_BLOCK FB_ProcessControl
       METHOD Process
           ValidateInputs();      // 입력 검증
           CalculateSetpoint();   // 설정값 계산
           ExecuteControl();      // 제어 실행
           UpdateOutputs();       // 출력 갱신
       END_METHOD
   END_FUNCTION_BLOCK

2. 조건문 단순화
   // CASE 문 사용
   CASE state OF
       0: InitializeSystem();
       1: RunNormalOperation();
       2: HandleError();
   END_CASE

3. 복잡한 조건을 Boolean 변수로 추출
   isReadyToStart := (sensor1Active AND sensor2Active AND NOT emergencyStop);
   IF isReadyToStart THEN
       StartOperation();
   END_IF

4. 상태 머신 패턴 적용
   // 복잡한 로직을 명확한 상태로 구조화

예시:

// ❌ 복잡도가 높은 코드
IF cond1 THEN
IF cond2 THEN
FOR i := 1 TO 10 DO
IF cond3 OR cond4 THEN
WHILE cond5 DO
// 많은 중첩...
END_WHILE
END_IF
END_FOR
END_IF
END_IF

// ✅ 리팩토링된 코드
IF NOT CanProcess() THEN
RETURN;
END_IF

ProcessItems(); // 별도 메소드로 분리

METHOD ProcessItems
FOR i := 1 TO 10 DO
ProcessSingleItem(i);
END_FOR
END_METHOD